├── .github ├── actions │ └── run-sentinel │ │ ├── Dockerfile │ │ ├── action.yml │ │ └── entrypoint.sh └── workflows │ ├── aws_pull_request.yml │ ├── azure_pull_request.yml │ ├── gcp_pull_request.yml │ └── vmware_pull_request.yml ├── README.md ├── Using-Sentinel-Policies-Across-Multiple-TFC-Orgs.pptx ├── aws ├── aws-functions │ ├── aws-functions.sentinel │ └── docs │ │ ├── determine_role_arn.md │ │ ├── find_resources_with_standard_tags.md │ │ ├── get_assumed_roles.md │ │ ├── validate_assumed_roles_with_list.md │ │ └── validate_assumed_roles_with_map.md ├── enforce-mandatory-tags.sentinel ├── restrict-ec2-instance-type.sentinel ├── sentinel.hcl └── test │ ├── enforce-mandatory-tags │ ├── fail-missing-tags.json │ ├── fail-no-tags.json │ ├── mock-tfconfig-fail-missing-tags.sentinel │ ├── mock-tfconfig-fail-no-tags.sentinel │ ├── mock-tfconfig-pass.sentinel │ ├── mock-tfplan-fail-missing-tags.sentinel │ ├── mock-tfplan-fail-no-tags.sentinel │ ├── mock-tfplan-pass.sentinel │ └── pass.json │ └── restrict-ec2-instance-type │ ├── fail.json │ ├── mock-tfplan-fail.sentinel │ ├── mock-tfplan-pass.sentinel │ └── pass.json ├── azure ├── enforce-mandatory-tags.sentinel ├── restrict-vm-size.sentinel ├── sentinel.hcl └── test │ ├── enforce-mandatory-tags │ ├── fail.json │ ├── mock-tfplan-fail.sentinel │ ├── mock-tfplan-pass.sentinel │ └── pass.json │ └── restrict-vm-size │ ├── fail.json │ ├── mock-tfplan-fail.sentinel │ ├── mock-tfplan-pass.sentinel │ └── pass.json ├── common-functions ├── tfconfig-functions │ ├── docs │ │ ├── filter_attribute_in_list.md │ │ ├── filter_attribute_not_in_list.md │ │ ├── find_all_datasources.md │ │ ├── find_all_module_calls.md │ │ ├── find_all_outputs.md │ │ ├── find_all_providers.md │ │ ├── find_all_provisioners.md │ │ ├── find_all_resources.md │ │ ├── find_all_variables.md │ │ ├── find_datasources_by_provider.md │ │ ├── find_datasources_by_type.md │ │ ├── find_datasources_in_module.md │ │ ├── find_descendant_modules.md │ │ ├── find_module_calls_in_module.md │ │ ├── find_outputs_by_sensitivity.md │ │ ├── find_outputs_in_module.md │ │ ├── find_providers_by_type.md │ │ ├── find_providers_in_module.md │ │ ├── find_provisioners_by_type.md │ │ ├── find_resources_by_provider.md │ │ ├── find_resources_by_type.md │ │ ├── find_resources_in_module.md │ │ ├── find_variables_in_module.md │ │ ├── print_violations.md │ │ └── to_string.md │ └── tfconfig-functions.sentinel ├── tfplan-functions │ ├── docs │ │ ├── evaluate_attribute.md │ │ ├── filter_attribute_contains_items_from_list.md │ │ ├── filter_attribute_contains_items_not_in_list.md │ │ ├── filter_attribute_does_not_have_prefix.md │ │ ├── filter_attribute_does_not_have_suffix.md │ │ ├── filter_attribute_does_not_match_regex.md │ │ ├── filter_attribute_greater_than_value.md │ │ ├── filter_attribute_has_prefix.md │ │ ├── filter_attribute_has_suffix.md │ │ ├── filter_attribute_in_list.md │ │ ├── filter_attribute_is_not_value.md │ │ ├── filter_attribute_is_value.md │ │ ├── filter_attribute_less_than_value.md │ │ ├── filter_attribute_matches_regex.md │ │ ├── filter_attribute_not_contains_list.md │ │ ├── filter_attribute_not_in_list.md │ │ ├── find_blocks.md │ │ ├── find_datasources.md │ │ ├── find_datasources_being_destroyed.md │ │ ├── find_datasources_by_provider.md │ │ ├── find_resources.md │ │ ├── find_resources_being_destroyed.md │ │ ├── find_resources_by_provider.md │ │ ├── print_violations.md │ │ └── to_string.md │ └── tfplan-functions.sentinel ├── tfrun-functions │ ├── docs │ │ ├── limit_cost_and_percentage_increase.md │ │ ├── limit_cost_by_workspace_name.md │ │ └── limit_proposed_monthly_cost.md │ └── tfrun-functions.sentinel └── tfstate-functions │ ├── docs │ ├── evaluate_attribute.md │ ├── filter_attribute_contains_items_from_list.md │ ├── filter_attribute_contains_items_not_in_list.md │ ├── filter_attribute_does_not_have_prefix.md │ ├── filter_attribute_does_not_have_suffix.md │ ├── filter_attribute_does_not_match_regex.md │ ├── filter_attribute_greater_than_value.md │ ├── filter_attribute_has_prefix.md │ ├── filter_attribute_has_suffix.md │ ├── filter_attribute_in_list.md │ ├── filter_attribute_is_not_value.md │ ├── filter_attribute_is_value.md │ ├── filter_attribute_less_than_value.md │ ├── filter_attribute_matches_regex.md │ ├── filter_attribute_not_contains_list.md │ ├── filter_attribute_not_in_list.md │ ├── find_blocks.md │ ├── find_datasources.md │ ├── find_datasources_by_provider.md │ ├── find_resources.md │ ├── find_resources_by_provider.md │ ├── print_violations.md │ └── to_string.md │ └── tfstate-functions.sentinel ├── gcp ├── enforce-mandatory-labels.sentinel ├── restrict-gce-machine-type.sentinel ├── sentinel.hcl └── test │ ├── .DS_Store │ ├── enforce-mandatory-labels │ ├── fail.json │ ├── mock-tfplan-fail.sentinel │ ├── mock-tfplan-pass.sentinel │ └── pass.json │ └── restrict-gce-machine-type │ ├── fail.json │ ├── mock-tfplan-fail.sentinel │ ├── mock-tfplan-pass.sentinel │ └── pass.json └── vmware ├── restrict-vm-cpu-and-memory.sentinel ├── restrict-vm-disk-size.sentinel ├── sentinel.hcl └── test ├── restrict-vm-cpu-and-memory ├── fail-cpu-and-memory.json ├── fail-cpu.json ├── fail-memory.json ├── mock-tfplan-fail-cpu-and-memory.sentinel ├── mock-tfplan-fail-cpu.sentinel ├── mock-tfplan-fail-memory.sentinel ├── mock-tfplan-pass.sentinel └── pass.json └── restrict-vm-disk-size ├── fail.json ├── mock-tfplan-fail.sentinel ├── mock-tfplan-pass.sentinel └── pass.json /.github/actions/run-sentinel/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM thrashr888/sentinel-simulator 2 | 3 | LABEL "com.github.actions.name"="sentinel test" 4 | LABEL "com.github.actions.description"="Test Sentinel policies" 5 | LABEL "com.github.actions.icon"="terminal" 6 | LABEL "com.github.actions.color"="blue" 7 | 8 | LABEL "repository"="https://github.com/rberlind/sentinel-policy-sets-for-tfc" 9 | LABEL "homepage"="http://github.com/rberlind/sentinel-policy-sets-for-tfc" 10 | LABEL "maintainer"="Roger Berlind" 11 | 12 | RUN apk --no-cache add jq curl 13 | 14 | COPY entrypoint.sh /entrypoint.sh 15 | ENTRYPOINT ["/entrypoint.sh"] 16 | CMD ["."] 17 | -------------------------------------------------------------------------------- /.github/actions/run-sentinel/action.yml: -------------------------------------------------------------------------------- 1 | # action.yml 2 | name: 'Sentinel Test' 3 | description: 'Test Sentinel policies with the Sentinel Simulator' 4 | runs: 5 | using: 'docker' 6 | image: 'Dockerfile' 7 | -------------------------------------------------------------------------------- /.github/actions/run-sentinel/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | cd "$1" 5 | 6 | set +e 7 | OUTPUT=$(sh -c "sentinel test" 2>&1) 8 | SUCCESS=$? 9 | echo "$OUTPUT" 10 | set -e 11 | 12 | if [ $SUCCESS -eq 0 ]; then 13 | exit 0 14 | fi 15 | 16 | if [ "$STL_ACTION_COMMENT" = "1" ] || [ "$STL_ACTION_COMMENT" = "false" ]; then 17 | exit $SUCCESS 18 | fi 19 | 20 | FMT_TEST=$(echo "$OUTPUT" | sed -e "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g") 21 | COMMENT="#### \`sentinel test\` Failed 22 | \`\`\` 23 | $FMT_TEST 24 | \`\`\`" 25 | PAYLOAD=$(echo '{}' | jq --arg body "$COMMENT" '.body = $body') 26 | COMMENTS_URL=$(cat /github/workflow/event.json | jq -r .pull_request.comments_url) 27 | curl -s -S -H "Authorization: token $GITHUB_TOKEN" --header "Content-Type: application/json" --data "$PAYLOAD" "$COMMENTS_URL" > /dev/null 28 | 29 | exit $SUCCESS 30 | -------------------------------------------------------------------------------- /.github/workflows/aws_pull_request.yml: -------------------------------------------------------------------------------- 1 | name: sentinel-test-aws 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | paths: 7 | - 'aws/**' 8 | 9 | jobs: 10 | sentinel-test-aws: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # This step checks out the repository's code 14 | - name: checkout-code 15 | uses: actions/checkout@v2 16 | # This step runs `sentinel test` against the AWS policies 17 | - name: sentinel-test-aws 18 | uses: rberlind/sentinel-policy-sets-for-tfc/.github/actions/run-sentinel@master 19 | with: 20 | args: ./aws 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /.github/workflows/azure_pull_request.yml: -------------------------------------------------------------------------------- 1 | name: sentinel-test-azure 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | paths: 7 | - 'azure/**' 8 | 9 | jobs: 10 | sentinel-test-azure: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # This step checks out the repository's code 14 | - name: checkout-code 15 | uses: actions/checkout@v2 16 | # This step runs `sentinel test` against the Azure policies 17 | - name: sentinel-test-azure 18 | uses: rberlind/sentinel-policy-sets-for-tfc/.github/actions/run-sentinel@master 19 | with: 20 | args: ./azure 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /.github/workflows/gcp_pull_request.yml: -------------------------------------------------------------------------------- 1 | name: sentinel-test-gcp 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | paths: 7 | - 'gcp/**' 8 | 9 | jobs: 10 | sentinel-test-gcp: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # This step checks out the repository's code 14 | - name: checkout-code 15 | uses: actions/checkout@v2 16 | # This step runs `sentinel test` against the GCP policies 17 | - name: sentinel-test-gcp 18 | uses: rberlind/sentinel-policy-sets-for-tfc/.github/actions/run-sentinel@master 19 | with: 20 | args: ./gcp 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /.github/workflows/vmware_pull_request.yml: -------------------------------------------------------------------------------- 1 | name: sentinel-test-vmware 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | paths: 7 | - 'vmware/**' 8 | 9 | jobs: 10 | sentinel-test-vmware: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # This step checks out the repository's code 14 | - name: checkout-code 15 | uses: actions/checkout@v2 16 | # This step runs `sentinel test` against the VMware policies 17 | - name: sentinel-test-vmware 18 | uses: rberlind/sentinel-policy-sets-for-tfc/.github/actions/run-sentinel@master 19 | with: 20 | args: ./vmware 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sentinel Policy Sets For Use With Terraform Cloud 2 | This repository contains Sentinel [policy sets](https://www.terraform.io/docs/cloud/sentinel/manage-policies.html) for use with Terraform Cloud (TFC) and Terraform Enterprise (TFE). It was created for an [SE Hangout](https://www.hashicorp.com/webinars/solution-engineering-hangout-using-sentinel-across-terraform-cloud-organizations) I delivered on September 25, 2019. The slides for that webinar are also in this repository. I will add a link to the recording of the webinar when it is available. 3 | 4 | There are four policy sets, one each for AWS, Azure, GCP, and VMware. The first three each contain two policies that restrict the size of VMs and require specific tags or labels. The fourth contains a single policy that restricts the CPU and memory allocated to VMware VMs. 5 | 6 | I have also included [Sentinel Simulator](https://docs.hashicorp.com/sentinel/intro/getting-started/install) test cases for each policy that can be used to test them. 7 | 8 | Additionally, [GitHub Actions](https://help.github.com/en/articles/about-github-actions) are used to automatically run the Sentinel Simulator test cases whenever a pull request is done requesting the merging of changes to the policies into the master branch. There are four GitHub Action workflows, one for each of the four clouds. Each workflow is only triggered if the pull request includes changes in the associated cloud's policies or test cases. 9 | 10 | The Terraform code used by the Terraform Cloud workspaces against which the policies are checked is in the GitHub repository, [rberlind/rberlind/se-hangout-9-25-2019](https://github.com/rberlind/se-hangout-9-25-2019). 11 | -------------------------------------------------------------------------------- /Using-Sentinel-Policies-Across-Multiple-TFC-Orgs.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rberlind/sentinel-policy-sets-for-tfc/7b69009dc0216c98fe9134b06bd9bfdb2aa44ac7/Using-Sentinel-Policies-Across-Multiple-TFC-Orgs.pptx -------------------------------------------------------------------------------- /aws/aws-functions/aws-functions.sentinel: -------------------------------------------------------------------------------- 1 | # Common functions for use with the AWS provider 2 | 3 | ##### Imports ##### 4 | import "tfconfig-functions" as config 5 | import "tfplan/v2" as tfplan 6 | import "strings" 7 | 8 | ##### Functions ##### 9 | 10 | ### find_resources_with_standard_tags ### 11 | find_resources_with_standard_tags = func() { 12 | resources = filter tfplan.resource_changes as address, rc { 13 | rc.provider_name is "aws" and 14 | rc.type not in ["aws_autoscaling_group"] and 15 | rc.mode is "managed" and 16 | (rc.change.actions contains "create" or rc.change.actions contains "update") 17 | } 18 | 19 | return resources 20 | } 21 | 22 | ### determine_role_arn ### 23 | # This can only determine the role_arn if it is set to either a hard-coded value 24 | # or to a reference to a single Terraform variable. 25 | # It sets the role to "complex" if it finds a single non-variable reference 26 | # or if it finds multiple references. 27 | # It sets the role to "none" if no role arn is found. 28 | determine_role_arn = func(address, data) { 29 | 30 | # Return empty string if provider does not assume a role 31 | role_arn_value = "none" 32 | 33 | # Check for role_arn 34 | if (length(data.config) else 0) > 0 and 35 | (length(data.config.assume_role) else 0) > 0 and 36 | data.config.assume_role[0].role_arn else null is not null { 37 | role_arn_data = data.config.assume_role[0].role_arn 38 | # Check for constant value or references 39 | if role_arn_data.constant_value else null is not null { 40 | # role_arn of AWS provider was hard-coded role_arn 41 | #print("Found a single constant value for role_arn.") 42 | role_arn_value = role_arn_data.constant_value 43 | } else if role_arn_data.references else [] is not [] { 44 | if length(role_arn_data.references) == 1 { 45 | # Process references 46 | role_arn = role_arn_data.references[0] 47 | if role_arn matches "var\\.(.*)" { 48 | # role_arn of AWS provider was a variable 49 | #print("Found a single variable reference for role_arn.") 50 | role_arn_variable = strings.trim_prefix(role_arn, "var.") 51 | role_arn_value = tfplan.variables[role_arn_variable].value 52 | } else { 53 | # reference was not a variable 54 | print("Found a single reference in the role_arn attribute,", 55 | "for provider", address, "but it was not a variable.") 56 | print("This policy only handles a role_arn attribute that is", 57 | "a constant value or a single reference to a variable.") 58 | # Set role_arn_value to null to cause failure of policy 59 | role_arn_value = "complex" 60 | } // end if role_arn is variable 61 | } else { 62 | print("Found more than one reference in the role_arn attribute", 63 | "for provider", address) 64 | print("This policy only handles a role_arn attribute that is", 65 | "a constant value or a single reference to a variable.") 66 | # Set role_arn_value to null to cause failure of policy 67 | role_arn_value = "complex" 68 | } // end if single reference 69 | } // end if constant_value or references 70 | } else { 71 | #print("Did not find role_arn.") 72 | } // end if assume_role.role_arn in config 73 | 74 | return role_arn_value 75 | } 76 | 77 | ### get_assumed_roles ### 78 | # Get assumed roles from all AWS providers 79 | # Please note that the assumed roles returned could include "none" or "complex"; 80 | # See the comments for the determine_role_arn function above. 81 | get_assumed_roles = func() { 82 | 83 | # Initialize empty map of roles indexed by aliases 84 | assumed_roles = {} 85 | 86 | # Get all AWS provider aliases 87 | aws_providers = config.find_providers_by_type("aws") 88 | 89 | # Iterate through all AWS provider aliases 90 | for aws_providers as address, data { 91 | assumed_roles[address] = determine_role_arn(address, data) 92 | } // end aws_providers 93 | 94 | return assumed_roles 95 | 96 | } 97 | 98 | ### validate_assumed_roles_with_list ### 99 | # Validate that all assumed roles are allowed. 100 | # If you want to the policy to pass if an assumed role contains a single 101 | # non-variable reference or if it finds multiple references, then include a role 102 | # called "complex" in the allowed_roles list. 103 | validate_assumed_roles_with_list = func(allowed_roles) { 104 | 105 | validated = true 106 | 107 | assumed_roles = get_assumed_roles() 108 | 109 | for assumed_roles as address, role { 110 | if role is not "none" and role not in allowed_roles { 111 | print("AWS provider", address, "has assumed role", 112 | role, "that is not allowed.") 113 | validated = false 114 | } 115 | } 116 | 117 | return validated 118 | } 119 | 120 | ### validate_assumed_roles_with_map ### 121 | # Validate that all assumed roles are allowed for the current workspace. 122 | # If you want to a policy to pass if an assumed role contains a single 123 | # non-variable reference or if it finds multiple references, then include a role 124 | # called "complex" in the map passed to this function and associate it 125 | # with workspaces. 126 | validate_assumed_roles_with_map = func(roles_map, workspace_name) { 127 | 128 | validated = true 129 | 130 | assumed_roles = get_assumed_roles() 131 | 132 | for assumed_roles as address, role { 133 | if role is not "none" { 134 | if role not in keys(roles_map) { 135 | print("AWS provider", address, "has assumed role", 136 | role, "that is not allowed.") 137 | validated = false 138 | } else { 139 | # Validate that role is allowed for current workspace 140 | matched = false 141 | for roles_map[role] as workspace_regex { 142 | if workspace_name matches workspace_regex { 143 | matched = true 144 | } 145 | } // end for workspace_regex 146 | if not matched { 147 | print("Workspace", workspace_name, "is not allowed to use role", role) 148 | print("It used that role in the AWS provider", address) 149 | validated = false 150 | } // end matched check 151 | } // end role in roles_map 152 | } // end if role is not "" 153 | } // end for assumed_roles 154 | 155 | return validated 156 | } 157 | -------------------------------------------------------------------------------- /aws/aws-functions/docs/determine_role_arn.md: -------------------------------------------------------------------------------- 1 | # determine_role_arn 2 | This function determines the ARN of an AWS IAM role assumed by the Terraform AWS provider using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) and [tfplan/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html) imports. 3 | 4 | It can only do this when the `role_arn` of the AWS provider is set to a hard-coded string or to a variable within the Terraform configuration. In the second case, the function cross-references the name of the variable in the tfconfig/v2 import with the actual value assigned to it in the tfplan/v2 import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [aws-functions.sentinel](../aws-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `determine_role_arn = func(address, data)` 11 | 12 | ## Arguments 13 | * **address**: the address of the provider which has the form `module_address:provider.alias`. 14 | * **data**: the data associated with the provider. 15 | 16 | ## Common Functions Used 17 | None 18 | 19 | ## What It Returns 20 | This function returns the ARN of the AWS IAM role of the provider. However, if no role was specified for an instance of the AWS provider, it returns "none", and if it finds finds a single non-variable reference or multiple references, it returns "complex". 21 | 22 | ## What It Prints 23 | This function prints warning messages if the `role_arn` attribute was not a hard-coded string or a reference to a single variable. 24 | 25 | ## Examples 26 | Here is an example of calling this function, assuming that the [tfconfig-functions.sentinel](../../../common-functions/tfconfig-functions/tfconfig-functions.sentinel) module has been imported with the alias `config`: 27 | ``` 28 | aws_providers = config.find_providers_by_type("aws") 29 | for aws_providers as address, data { 30 | assumed_roles[address] = determine_role_arn(address, data) 31 | } 32 | ``` 33 | 34 | This function is called by the `get_assumed_roles` function contained in the same Sentinel module. In fact, the above code is extracted from that function. Since the two functions are in the same module, the call to the `get_assumed_roles` function does not include the `aws.` prefix. 35 | -------------------------------------------------------------------------------- /aws/aws-functions/docs/find_resources_with_standard_tags.md: -------------------------------------------------------------------------------- 1 | # find_resources_with_standard_tags 2 | This function finds all resource instances for the AWS provider that use standard AWS tags in the current plan that are being created or modified using the [tfplan/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html) import. 3 | 4 | Currently, the only AWS resource excluded is `aws_autoscaling_group`. If you discover other AWS resources that do not use the `tags` attribute in the standard way, then add them to the list that already includes `aws_autoscaling_group`. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [aws-functions.sentinel](../aws-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `find_resources_with_standard_tags = func()` 11 | 12 | ## Arguments 13 | * None 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of resource instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here is an example of calling this function, assuming that the aws-functions.sentinel file that contains it has been imported with the alias `aws`: 26 | ``` 27 | allAWSResourcesWithStandardTags = aws.find_resources_with_standard_tags() 28 | ``` 29 | 30 | This function is used by the [enforce-mandatory-tags.sentinel](../../enforce-mandatory-tags.sentinel) policy. 31 | -------------------------------------------------------------------------------- /aws/aws-functions/docs/get_assumed_roles.md: -------------------------------------------------------------------------------- 1 | # get_assumed_roles 2 | This function gets all roles assumed by any instances of the AWS provider in the current Terraform configuration using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) and [tfplan/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html) imports. 3 | 4 | The tfplan/v2 import is used by the `determine_role_arn` function that this function calls. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [aws-functions.sentinel](../aws-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `get_assumed_roles = func()` 11 | 12 | ## Arguments 13 | None 14 | 15 | ## Common Functions Used 16 | This function calls the `find_providers_by_type` function of the [tfconfig-functions.sentinel](../../../common-functions/tfconfig-functions/tfconfig-functions.sentinel) module and the `determine_role_arn` function of the [aws-functions.sentinel](../aws-functions.sentinel) module. 17 | 18 | ## What It Returns 19 | This function returns a map indexed by the addresses of the provider instances contained in the workspace's Terraform configuration with values set to the actual ARNs of the AWS IAM roles assumed by those providers. However, if no role was specified for an instance of the AWS provider, it returns "none" for that instance, and if it finds finds a single non-variable reference or multiple references for an instance, it returns "complex" for that instance. 20 | 21 | ## What It Prints 22 | This function does not print anything itself, but the `determine_role_arn` function prints warning messages if the `role_arn` attribute was not a hard-coded string or a reference to a single variable. 23 | 24 | ## Examples 25 | Here is an example of calling this function: 26 | ``` 27 | assumed_roles = get_assumed_roles() 28 | ``` 29 | 30 | This function is called by the `validate_assumed_roles_with_list` and `validate_assumed_roles_with_map` functions contained in the same Sentinel module. Since the three functions are in the same module, the call to the `get_assumed_roles` function does not include the `aws.` prefix. 31 | -------------------------------------------------------------------------------- /aws/aws-functions/docs/validate_assumed_roles_with_list.md: -------------------------------------------------------------------------------- 1 | # validate_assumed_roles_with_list 2 | This function checks whether all roles assumed by all instances of the AWS provider in the current Terraform configuration are in a specified list. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [aws-functions.sentinel](../aws-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `validate_assumed_roles_with_list = func(allowed_roles)` 9 | 10 | ## Arguments 11 | * **allowed_roles**: a list of allowed AWS IAM role ARNs that can be assumed by AWS providers. If you want to a policy that calls this function to pass if a role assumed by an instance of the AWS provider contains a single non-variable reference or multiple references, include "complex" in the list. 12 | 13 | ## Common Functions Used 14 | This function calls the the `get_assumed_roles` function of the [aws-functions.sentinel](../aws-functions.sentinel) module. 15 | 16 | ## What It Returns 17 | This function returns `true` if all the AWS IAM roles assumed by AWS providers in the Terraform configuration of the current workspace were in the `allowed_roles` list. Otherwise, it returns `false`. 18 | 19 | ## What It Prints 20 | This function prints a warning message for each role assumed by an AWS provider that is not in the `allowed_roles` list. 21 | 22 | ## Examples 23 | Here is an example of calling this function, assuming that the aws-functions.sentinel file that contains it has been imported with the alias `aws`: 24 | ``` 25 | allowed_roles = [ 26 | "arn:aws:iam::123412341234:role/terraform-assumed-role", 27 | ] 28 | roles_validated = aws.validate_assumed_roles_with_list(allowed_roles) 29 | ``` 30 | 31 | This function is used by the [restrict-assumed-roles.sentinel](../../restrict-assumed-roles.sentinel) policy. 32 | -------------------------------------------------------------------------------- /aws/aws-functions/docs/validate_assumed_roles_with_map.md: -------------------------------------------------------------------------------- 1 | # validate_assumed_roles_with_map 2 | This function validates whether all roles assumed by instances of the AWS provider are allowed for the current workspace based on a map that maps AWS IAM roles to regular expressions (regex) that are compared to the name of the workspace. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [aws-functions.sentinel](../aws-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `validate_assumed_roles_with_map = func(roles_map, workspace_name)` 9 | 10 | ## Arguments 11 | * **roles_map**: a map that associates AWS IAM role ARNs with lists of regular expressions (regex) that select workspace names that the role can be used in. If you want to a policy that calls this function to pass if a role assumed by an instance of the AWS provider contains a single non-variable reference or multiple references, include "complex" in the list. 12 | * **workspace_name**: the name of the workspace which can be derived from `tfrun.workspace.name`. 13 | 14 | ## Common Functions Used 15 | This function calls the the `get_assumed_roles` function of the [aws-functions.sentinel](../aws-functions.sentinel) module. 16 | 17 | ## What It Returns 18 | This function returns `true` if all the AWS IAM roles assumed by AWS providers in the Terraform configuration of the current workspace were keys in the `roles_map` map and the current workspace matched a regex in the lists assigned to values associated with those keys. Otherwise, it returns `false`. 19 | 20 | ## What It Prints 21 | This function prints a warning message for each role assumed by an AWS provider that is not a key in `roles_map` or that is a key in that map but `workspace_name` does not match any regex in the list associated with it. 22 | 23 | ## Examples 24 | Here is an example of calling this function, assuming that the aws-functions.sentinel file that contains it has been imported with the alias `aws`: 25 | ``` 26 | allowed_roles = { 27 | "arn:aws:iam::123412341234:role/role-dev": [ 28 | "(.*)-dev$", 29 | "^dev-(.*)", 30 | ], 31 | "arn:aws:iam::567856785678:role/role-qa": [ 32 | "(.*)-qa$", 33 | "^qa-(.*)", 34 | ], 35 | "arn:aws:iam::909012349090:role/role-prod": [ 36 | "(.*)-prod$", 37 | "^prod-(.*)", 38 | ], 39 | } 40 | workspace_name = tfrun.workspace.name 41 | roles_validated = aws.validate_assumed_roles_with_map(allowed_roles, workspace_name) 42 | ``` 43 | 44 | This function is used by the [restrict-assumed-roles-by-workspace.sentinel](../../restrict-assumed-roles-by-workspace.sentinel) policy. 45 | -------------------------------------------------------------------------------- /aws/enforce-mandatory-tags.sentinel: -------------------------------------------------------------------------------- 1 | # This policy uses the Sentinel tfplan/v2 import to require that 2 | # all AWS resources that use standard AWS tags have all mandatory tags 3 | 4 | # Import common-functions/tfplan-functions/tfplan-functions.sentinel 5 | # with alias "plan" 6 | import "tfplan-functions" as plan 7 | 8 | # Import aws-functions/aws-functions.sentinel 9 | # with alias "aws" 10 | import "aws-functions" as aws 11 | 12 | # List of mandatory tags 13 | mandatory_tags = ["Name", "ttl", "Owner"] 14 | 15 | # Get all AWS Resources with standard tags 16 | allAWSResourcesWithStandardTags = aws.find_resources_with_standard_tags() 17 | 18 | # Filter to AWS resources with violations 19 | # Warnings will be printed for all violations since the last parameter is true 20 | violatingAWSResources = plan.filter_attribute_not_contains_list(allAWSResourcesWithStandardTags, 21 | "tags", mandatory_tags, true) 22 | 23 | # Main rule 24 | main = rule { 25 | length(violatingAWSResources["messages"]) is 0 26 | } 27 | -------------------------------------------------------------------------------- /aws/restrict-ec2-instance-type.sentinel: -------------------------------------------------------------------------------- 1 | # This policy uses the Sentinel tfplan/v2 import to require that 2 | # all EC2 instances have instance types from an allowed list 3 | 4 | # Import common-functions/tfplan-functions/tfplan-functions.sentinel 5 | # with alias "plan" 6 | import "tfplan-functions" as plan 7 | 8 | # Allowed EC2 Instance Types 9 | # Include "null" to allow missing or computed values 10 | allowed_types = ["t2.small", "t2.medium", "t2.large"] 11 | 12 | # Get all EC2 instances 13 | allEC2Instances = plan.find_resources("aws_instance") 14 | 15 | # Filter to EC2 instances with violations 16 | # Warnings will be printed for all violations since the last parameter is true 17 | violatingEC2Instances = plan.filter_attribute_not_in_list(allEC2Instances, 18 | "instance_type", allowed_types, true) 19 | 20 | # Count violations 21 | violations = length(violatingEC2Instances["messages"]) 22 | 23 | # Main rule 24 | main = rule { 25 | violations is 0 26 | } 27 | -------------------------------------------------------------------------------- /aws/sentinel.hcl: -------------------------------------------------------------------------------- 1 | module "tfplan-functions" { 2 | source = "../common-functions/tfplan-functions/tfplan-functions.sentinel" 3 | } 4 | 5 | module "tfstate-functions" { 6 | source = "../common-functions/tfstate-functions/tfstate-functions.sentinel" 7 | } 8 | 9 | module "tfconfig-functions" { 10 | source = "../common-functions/tfconfig-functions/tfconfig-functions.sentinel" 11 | } 12 | 13 | module "aws-functions" { 14 | source = "./aws-functions/aws-functions.sentinel" 15 | } 16 | 17 | policy "enforce-mandatory-tags" { 18 | source = "./enforce-mandatory-tags.sentinel" 19 | enforcement_level = "advisory" 20 | } 21 | 22 | policy "restrict-ec2-instance-type" { 23 | source = "./restrict-ec2-instance-type.sentinel" 24 | enforcement_level = "advisory" 25 | } 26 | -------------------------------------------------------------------------------- /aws/test/enforce-mandatory-tags/fail-missing-tags.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | }, 6 | "tfconfig-functions": { 7 | "path": "../../../common-functions/tfconfig-functions/tfconfig-functions.sentinel" 8 | }, 9 | "aws-functions": { 10 | "path": "../../aws-functions/aws-functions.sentinel" 11 | } 12 | }, 13 | "mock": { 14 | "tfplan/v2": "mock-tfplan-fail-missing-tags.sentinel", 15 | "tfconfig/v2": "mock-tfconfig-fail-missing-tags.sentinel" 16 | }, 17 | "test": { 18 | "main": false 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /aws/test/enforce-mandatory-tags/fail-no-tags.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | }, 6 | "tfconfig-functions": { 7 | "path": "../../../common-functions/tfconfig-functions/tfconfig-functions.sentinel" 8 | }, 9 | "aws-functions": { 10 | "path": "../../aws-functions/aws-functions.sentinel" 11 | } 12 | }, 13 | "mock": { 14 | "tfplan/v2": "mock-tfplan-fail-no-tags.sentinel", 15 | "tfconfig/v2": "mock-tfconfig-fail-no-tags.sentinel" 16 | }, 17 | "test": { 18 | "main": false 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /aws/test/enforce-mandatory-tags/mock-tfconfig-fail-no-tags.sentinel: -------------------------------------------------------------------------------- 1 | import "strings" 2 | 3 | providers = { 4 | "aws": { 5 | "alias": "", 6 | "config": { 7 | "region": { 8 | "references": [ 9 | "var.aws_region", 10 | ], 11 | }, 12 | }, 13 | "module_address": "", 14 | "name": "aws", 15 | "provider_config_key": "aws", 16 | "version_constraint": "", 17 | }, 18 | } 19 | 20 | resources = { 21 | "aws_s3_bucket.bucket": { 22 | "address": "aws_s3_bucket.bucket", 23 | "config": { 24 | "acl": { 25 | "references": [ 26 | "var.bucket_acl", 27 | ], 28 | }, 29 | "bucket": { 30 | "references": [ 31 | "var.bucket_name", 32 | ], 33 | }, 34 | "logging": [ 35 | { 36 | "target_bucket": { 37 | "constant_value": "roger-tf", 38 | }, 39 | }, 40 | ], 41 | "server_side_encryption_configuration": [ 42 | { 43 | "rule": [ 44 | { 45 | "apply_server_side_encryption_by_default": [ 46 | { 47 | "kms_master_key_id": { 48 | "constant_value": "arn:aws:kms:us-east-1:753646501470:key/00c892e8-40c4-4048-a650-0f755876503d", 49 | }, 50 | "sse_algorithm": { 51 | "constant_value": "aws:kms", 52 | }, 53 | }, 54 | ], 55 | }, 56 | ], 57 | }, 58 | ], 59 | "website": [ 60 | { 61 | "index_document": { 62 | "constant_value": "index.html", 63 | }, 64 | "routing_rules": { 65 | "constant_value": "[{\n \"Condition\": {\n \"KeyPrefixEquals\": \"docs/\"\n },\n \"Redirect\": {\n \"ReplaceKeyPrefixWith\": \"documents/\"\n }\n}]\n", 66 | }, 67 | }, 68 | ], 69 | }, 70 | "count": {}, 71 | "depends_on": [], 72 | "for_each": {}, 73 | "mode": "managed", 74 | "module_address": "", 75 | "name": "bucket", 76 | "provider_config_key": "aws", 77 | "provisioners": [], 78 | "type": "aws_s3_bucket", 79 | }, 80 | } 81 | 82 | provisioners = {} 83 | 84 | variables = { 85 | "aws_region": { 86 | "default": "us-east-1", 87 | "description": "AWS region", 88 | "module_address": "", 89 | "name": "aws_region", 90 | }, 91 | "bucket_acl": { 92 | "default": "private", 93 | "description": "ACL for S3 bucket: private, public-read, public-read-write, etc", 94 | "module_address": "", 95 | "name": "bucket_acl", 96 | }, 97 | "bucket_name": { 98 | "default": null, 99 | "description": "Name of the bucket to create", 100 | "module_address": "", 101 | "name": "bucket_name", 102 | }, 103 | } 104 | 105 | outputs = { 106 | "sse": { 107 | "depends_on": [], 108 | "description": "", 109 | "module_address": "", 110 | "name": "sse", 111 | "sensitive": false, 112 | "value": { 113 | "references": [ 114 | "aws_s3_bucket.bucket", 115 | ], 116 | }, 117 | }, 118 | } 119 | 120 | module_calls = {} 121 | 122 | strip_index = func(addr) { 123 | s = strings.split(addr, ".") 124 | for s as i, v { 125 | s[i] = strings.split(v, "[")[0] 126 | } 127 | 128 | return strings.join(s, ".") 129 | } 130 | -------------------------------------------------------------------------------- /aws/test/enforce-mandatory-tags/pass.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | }, 6 | "tfconfig-functions": { 7 | "path": "../../../common-functions/tfconfig-functions/tfconfig-functions.sentinel" 8 | }, 9 | "aws-functions": { 10 | "path": "../../aws-functions/aws-functions.sentinel" 11 | } 12 | }, 13 | "mock": { 14 | "tfplan/v2": "mock-tfplan-pass.sentinel", 15 | "tfconfig/v2": "mock-tfconfig-pass.sentinel" 16 | }, 17 | "test": { 18 | "main": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /aws/test/restrict-ec2-instance-type/fail.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-fail.sentinel" 9 | }, 10 | "test": { 11 | "main": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /aws/test/restrict-ec2-instance-type/pass.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-pass.sentinel" 9 | }, 10 | "test": { 11 | "main": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /azure/enforce-mandatory-tags.sentinel: -------------------------------------------------------------------------------- 1 | # This policy uses the Sentinel tfplan/v2 import to require that 2 | # all Azure VMs have all mandatory tags 3 | 4 | # Import common-functions/tfplan-functions/tfplan-functions.sentinel 5 | # with alias "plan" 6 | import "tfplan-functions" as plan 7 | 8 | # List of mandatory tags 9 | mandatory_tags = ["environment"] 10 | 11 | # Get all Azure VMs 12 | allAzureVMs = plan.find_resources("azurerm_virtual_machine") 13 | 14 | # Filter to Azure VMs with violations 15 | # Warnings will be printed for all violations since the last parameter is true 16 | violatingAzureVMs = plan.filter_attribute_not_contains_list(allAzureVMs, 17 | "tags", mandatory_tags, true) 18 | 19 | # Main rule 20 | main = rule { 21 | length(violatingAzureVMs["messages"]) is 0 22 | } 23 | -------------------------------------------------------------------------------- /azure/restrict-vm-size.sentinel: -------------------------------------------------------------------------------- 1 | # This policy uses the Sentinel tfplan/v2 import to require that 2 | # all Azure VMs have vm sizes from an allowed list 3 | 4 | # Import common-functions/tfplan-functions/tfplan-functions.sentinel 5 | # with alias "plan" 6 | import "tfplan-functions" as plan 7 | 8 | # Allowed Azure VM Sizes 9 | # Include "null" to allow missing or computed values 10 | allowed_sizes = ["Standard_A1", "Standard_A2", "Standard_D1_v2", "Standard_D2_v2"] 11 | 12 | # Get all Azure VMs 13 | allAzureVMs = plan.find_resources("azurerm_virtual_machine") 14 | 15 | # Filter to Azure VMs with violations 16 | # Warnings will be printed for all violations since the last parameter is true 17 | violatingAzureVMs = plan.filter_attribute_not_in_list(allAzureVMs, 18 | "vm_size", allowed_sizes, true) 19 | 20 | # Count violations 21 | violations = length(violatingAzureVMs["messages"]) 22 | 23 | # Main rule 24 | main = rule { 25 | violations is 0 26 | } 27 | -------------------------------------------------------------------------------- /azure/sentinel.hcl: -------------------------------------------------------------------------------- 1 | module "tfplan-functions" { 2 | source = "../common-functions/tfplan-functions/tfplan-functions.sentinel" 3 | } 4 | 5 | module "tfstate-functions" { 6 | source = "../common-functions/tfstate-functions/tfstate-functions.sentinel" 7 | } 8 | 9 | module "tfconfig-functions" { 10 | source = "../common-functions/tfconfig-functions/tfconfig-functions.sentinel" 11 | } 12 | 13 | policy "enforce-mandatory-tags" { 14 | source = "./enforce-mandatory-tags.sentinel" 15 | enforcement_level = "advisory" 16 | } 17 | 18 | policy "restrict-vm-size" { 19 | source = "./restrict-vm-size.sentinel" 20 | enforcement_level = "advisory" 21 | } 22 | -------------------------------------------------------------------------------- /azure/test/enforce-mandatory-tags/fail.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-fail.sentinel" 9 | }, 10 | "test": { 11 | "main": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /azure/test/enforce-mandatory-tags/pass.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-pass.sentinel" 9 | }, 10 | "test": { 11 | "main": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /azure/test/restrict-vm-size/fail.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-fail.sentinel" 9 | }, 10 | "test": { 11 | "main": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /azure/test/restrict-vm-size/pass.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-pass.sentinel" 9 | }, 10 | "test": { 11 | "main": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/filter_attribute_in_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_in_list 2 | This function filters a collection of items such as providers, provisioners, resources, data sources, variables, outputs, or module calls to those with a top-level attribute that is contained in a provided list. A policy would call it when it wants the attribute to not have a value from the list. 3 | 4 | This function is intended to examine metadata of various Terraform objects within a Terraform configuration. It cannot be used to examine the values of attributes of resources or data sources. Use the filter functions of the tfplan-functions or tfstate-functions modules for that. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_in_list = func(items, attr, forbidden, prtmsg)` 11 | 12 | ## Arguments 13 | * **items**: a map of items such as providers, provisioners, resources, data sources, variables, outputs, or module calls. 14 | * **attr**: the name of a top-level attribute given as a string that must be in a given list. Nested attributes cannot be used by this function. 15 | * **forbidden**: a list of values the attribute is not allowed to have. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [to_string](./to_string.md) function. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `items` and `messages`. The `items` map contains the actual items of the original collection for which the attribute (`attr`) is in the list (`allowed`) while the `messages` map contains the violation messages associated with those items. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `plan`: 29 | ``` 30 | violatingProviders = config.filter_attribute_in_list(allProviders, 31 | "name", prohibited_list, false) 32 | 33 | violatingResources = config.filter_attribute_in_list(allResources, 34 | "type", prohibited_list, false) 35 | 36 | violatingProvisioners = config.filter_attribute_in_list(allProvisioners, 37 | "type", prohibited_list, false) 38 | ``` 39 | 40 | This function is used by several cloud-agnostic policies that prohibit certain types of items including [prohibited-datasources.sentinel](../../../cloud-agnostic/prohibited-datasources.sentinel), [prohibited-providers.sentinel](../../../cloud-agnostic/prohibited-providers.sentinel), [prohibited-provisioners.sentinel](../../../cloud-agnostic/prohibited-provisioners.sentinel), and [prohibited-resources.sentinel](../../../cloud-agnostic/prohibited-resources.sentinel). 41 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/filter_attribute_not_in_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_not_in_list 2 | This function filters a collection of items such as providers, provisioners, resources, data sources, variables, outputs, or module calls to those with a top-level attribute that is not contained in a provided list. A policy would call it when it wants the attribute to have a value from the list. 3 | 4 | This function is intended to examine metadata of various Terraform objects within a Terraform configuration. It cannot be used to examine the values of attributes of resources or data sources. Use the filter functions of the tfplan-functions or tfstate-functions modules for that. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_not_in_list = func(items, attr, allowed, prtmsg)` 11 | 12 | ## Arguments 13 | * **items**: a map of items such as providers, provisioners, resources, data sources, variables, outputs, or module calls. 14 | * **attr**: the name of a top-level attribute given as a string that must be in a given list. Nested attributes cannot be used by this function. 15 | * **allowed**: a list of values the attribute is allowed to have. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [to_string](./to_string.md) function. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `items` and `messages`. The `items` map contains the actual items of the original collection for which the attribute (`attr`) is not in the list (`allowed`) while the `messages` map contains the violation messages associated with those items. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `plan`: 29 | ``` 30 | violatingProviders = config.filter_attribute_not_in_list(allProviders, 31 | "name", allowed_list, false) 32 | 33 | violatingResources = config.filter_attribute_not_in_list(allResources, 34 | "type", allowed_list, false) 35 | 36 | violatingProvisioners = config.filter_attribute_not_in_list(allProvisioners, 37 | "type", allowed_list, false) 38 | ``` 39 | 40 | This function is used by several cloud-agnostic policies that allow certain types of items including [allowed-datasources.sentinel](../../../cloud-agnostic/allowed-datasources.sentinel), [allowed-providers.sentinel](../../../cloud-agnostic/allowed-providers.sentinel), [allowed-provisioners.sentinel](../../../cloud-agnostic/allowed-provisioners.sentinel), and [allowed-resources.sentinel](../../../cloud-agnostic/allowed-resources.sentinel). 41 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_all_datasources.md: -------------------------------------------------------------------------------- 1 | # find_all_datasources 2 | This function finds all data sources in all modules in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | Calling it is equivalent to filtering `tfconfig.resources` to those with `mode` equal to `data`, which indicates that they are data sources rather than managed resources. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `find_all_datasources = func()` 11 | 12 | ## Arguments 13 | None 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of data sources indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the data sources (excluding indices representing their counts). The map actually contains all data sources from the [`tfconfig.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-resources-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here is an example of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 26 | ``` 27 | allDatasources = config.find_all_datasources() 28 | ``` 29 | 30 | This function is used by the [prohibited-datasources.sentinel (Cloud Agnostic)](../../../cloud-agnostic/prohibited-datasources.sentinel) and [allowed-datasources.sentinel (Cloud Agnostic)](../../../cloud-agnostic/allowed-datasources.sentinel) policies. 31 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_all_module_calls.md: -------------------------------------------------------------------------------- 1 | # find_all_module_calls 2 | This function finds all module calls in all modules in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | Calling it is equivalent to referencing `tfconfig.module_calls`. It is included so that policies that use the tfconfig-functions.sentinel module do not need to import both it and the tfconfig/v2 module. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `find_all_module_calls = func()` 11 | 12 | ## Arguments 13 | None 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of all module_calls indexed by the address of the module_call's module and its name. The map actually is identical to the [`tfconfig.module_calls`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-module_calls-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here is an example of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 26 | ``` 27 | allModuleCalls = config.find_all_module_calls() 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_all_outputs.md: -------------------------------------------------------------------------------- 1 | # find_all_outputs 2 | This function finds all outputs in all modules in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | Calling it is equivalent to referencing `tfconfig.outputs`. It is included so that policies that use the tfconfig-functions.sentinel module do not need to import both it and the tfconfig/v2 module. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `find_all_outputs = func()` 11 | 12 | ## Arguments 13 | None 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of all outputs indexed by the address of the output's module and its name. The map actually is identical to the [`tfconfig.outputs`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-outputs-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here is an example of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 26 | ``` 27 | allOutputs = config.find_all_outputs() 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_all_providers.md: -------------------------------------------------------------------------------- 1 | # find_all_providers 2 | This function finds all providers in all modules in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | Calling it is equivalent to referencing `tfconfig.providers`. It is included so that policies that use the tfconfig-functions.sentinel module do not need to import both it and the tfconfig/v2 module. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `find_all_providers = func()` 11 | 12 | ## Arguments 13 | None 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of all providers indexed by the address of the provider's module and the provider's name and alias. The map actually is identical to the [`tfconfig.providers`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-providers-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here is an example of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 26 | ``` 27 | allProviders = config.find_all_providers() 28 | ``` 29 | 30 | This function is used by the [prohibited-providers.sentinel (Cloud Agnostic)](../../../cloud-agnostic/prohibited-providers.sentinel) and [allowed-providers.sentinel (Cloud Agnostic)](../../../cloud-agnostic/allowed-providers.sentinel) policies. 31 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_all_provisioners.md: -------------------------------------------------------------------------------- 1 | # find_all_provisioners 2 | This function finds all provisioners in all modules in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | Calling it is equivalent to referencing `tfconfig.provisioners`. It is included so that policies that use the tfconfig-functions.sentinel module do not need to import both it and the tfconfig/v2 module. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `find_all_provisioners = func()` 11 | 12 | ## Arguments 13 | None 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of all provisioners indexed by the address of the resource the provisioner is attached to and the provisioner's own index within that resource's provisioners. The map actually is identical to the [`tfconfig.provisioners`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-provisioners-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here is an example of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 26 | ``` 27 | allProvisioners = config.find_all_provisioners() 28 | ``` 29 | 30 | This function is used by the [prohibited-provisioners.sentinel (Cloud Agnostic)](../../../cloud-agnostic/prohibited-provisioners.sentinel) and [allowed-provisioners.sentinel (Cloud Agnostic)](../../../cloud-agnostic/allowed-provisioners.sentinel) policies. 31 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_all_resources.md: -------------------------------------------------------------------------------- 1 | # find_all_resources 2 | This function finds all managed resources in all modules in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | Calling it is equivalent to filtering `tfconfig.resources` to those with `mode` equal to `managed`, which indicates that they are managed resources rather than data sources. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `find_all_resources = func()` 11 | 12 | ## Arguments 13 | None 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of managed resources indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources (excluding indices representing their counts). The map actually contains all managed resources from the [`tfconfig.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-resources-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here is an example of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 26 | ``` 27 | allResources = config.find_all_resources() 28 | ``` 29 | 30 | This function is used by the [prohibited-resources.sentinel (Cloud Agnostic)](../../../cloud-agnostic/prohibited-resources.sentinel) and [allowed-resources.sentinel (Cloud Agnostic)](../../../cloud-agnostic/allowed-resources.sentinel) policies. 31 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_all_variables.md: -------------------------------------------------------------------------------- 1 | # find_all_variables 2 | This function finds all variables in all modules in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | Calling it is equivalent to referencing `tfconfig.variables`. It is included so that policies that use the tfconfig-functions.sentinel module do not need to import both it and the tfconfig/v2 module. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `find_all_variables = func()` 11 | 12 | ## Arguments 13 | None 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of all variables indexed by the address of the variable's module and its name. The map actually is identical to the [`tfconfig.variables`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-variables-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here is an example of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 26 | ``` 27 | allVariables = config.find_all_variables() 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_datasources_by_provider.md: -------------------------------------------------------------------------------- 1 | # find_datasources_by_provider 2 | This function finds all data sources created by a specific provider in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_datasources_by_provider = func(provider)` 9 | 10 | ## Arguments 11 | * **provider**: the provider of data sources to find, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of data sources indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the data sources (excluding indices representing their counts). The map is actually a filtered sub-collection of the [`tfconfig.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-resources-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | allAWSDatasources = config.find_datasources_by_provider("aws") 26 | 27 | allAzureDatasources = config.find_datasources_by_provider("azurerm") 28 | 29 | allGoogleDatasources = config.find_datasources_by_provider("google") 30 | 31 | allVMwareDatasources = config.find_datasources_by_provider("vsphere") 32 | ``` 33 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_datasources_by_type.md: -------------------------------------------------------------------------------- 1 | # find_datasources_by_type 2 | This function finds all data sources of a specific type in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_datasources_by_type = func(type)` 9 | 10 | ## Arguments 11 | * **type**: the type of data source to find, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of data sources indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the data sources (excluding indices representing their counts). The map is actually a filtered sub-collection of the [`tfconfig.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-resources-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | allAMIs = config.find_datasources_by_type("aws_ami") 26 | 27 | allImages = config.find_datasources_by_type("azurerm_image") 28 | 29 | allImages = config.find_datasources_by_type("google_compute_image") 30 | 31 | allDatastores = config.find_datasources_by_type("vsphere_datastore") 32 | ``` 33 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_datasources_in_module.md: -------------------------------------------------------------------------------- 1 | # find_datasources_in_module 2 | This function finds all data sources in a specific module in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_datasources_in_module = func(module_address)` 9 | 10 | ## Arguments 11 | * **module_address**: the address of the module containing data sources to find, given as a string. The root module is represented by "". A module named `network` called by the root module is represented by "module.network". if that module contained a module named `subnets`, it would be represented by "module.network.module.subnets". 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of data sources indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the data sources (excluding indices representing their counts). The map is actually a filtered sub-collection of the [`tfconfig.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-resources-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | allRootModuleDatasources = config.find_datasources_in_module("") 26 | 27 | allNetworkDatasources = config.find_datasources_in_module("module.network") 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_descendant_modules.md: -------------------------------------------------------------------------------- 1 | # find_descendant_modules 2 | This function finds the addresses of all modules called directly or indirectly by a module in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | It does this by calling itself recursively. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `find_descendant_modules = func(module_address)` 11 | 12 | ## Arguments 13 | * **module_address**: the address of the module containing descendant modules to find, given as a string. The root module is represented by "". A module named `network` called by the root module is represented by "module.network". if that module contained a module named `subnets`, it would be represented by "module.network.module.subnets". 14 | 15 | You can determine all module addresses in your current configuration by calling `find_descendant_modules("")`. 16 | 17 | ## Common Functions Used 18 | This function calls `find_module_calls_in_module()`. 19 | 20 | ## What It Returns 21 | This function returns a list of module addresses called directly or indirectly from the specified module. 22 | 23 | ## What It Prints 24 | This function does not print anything. 25 | 26 | ## Examples 27 | Here is an example of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 28 | ``` 29 | allModuleAddresses = config.find_descendant_modules("") 30 | ``` 31 | 32 | This function calls itself recursively with this code: 33 | ``` 34 | module_addresses += find_descendant_modules(new_module_address) 35 | ``` 36 | It does not use `config.` before calling itself since that is not necessary when calling a function from inside the module that contains it. 37 | 38 | It is also called by the [use-lastest-module-versions.sentinel](../../../cloud-agnostic/http-examples/use-lastest-module-versions.sentinel) policy. 39 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_module_calls_in_module.md: -------------------------------------------------------------------------------- 1 | # find_module_calls_in_module 2 | This function finds all direct module calls in a specific module in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_module_calls_in_module = func(module_address)` 9 | 10 | ## Arguments 11 | * **module_address**: the address of the module containing module_calls to find, given as a string. The root module is represented by "". A module named `network` called by the root module is represented by "module.network". if that module contained a module named `subnets`, it would be represented by "module.network.module.subnets". 12 | 13 | You can determine all module addresses in your current configuration by calling `find_descendant_modules("")`. 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of module calls indexed by the address of the module call's parent module and the module call's name. The map is actually a filtered sub-collection of the [`tfconfig.module_calls`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-module_calls-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 26 | ``` 27 | rootModuleCalls = config.find_module_calls_in_module("") 28 | 29 | networkModuleCalls = config.find_module_calls_in_module("module.network") 30 | ``` 31 | 32 | This function is called by the `find_descendant_modules` function of the tfconfig-functions.sentinel module. 33 | 34 | It is also called by the [use-lastest-module-versions.sentinel](../../../cloud-agnostic/http-examples/use-lastest-module-versions.sentinel) policy. 35 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_outputs_by_sensitivity.md: -------------------------------------------------------------------------------- 1 | # find_outputs_by_sensitivity 2 | This function finds all outputs of a specific sensitivity (`true` or `false`) in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_outputs_by_sensitivity = func(sensitive)` 9 | 10 | ## Arguments 11 | * **sensitive**: the desired sensitivity of outputs which can be `true` or `false` (without quotes). 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of outputs indexed by the address of the module and the name of the output. The map is actually a filtered sub-collection of the [`tfconfig.outputs`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-outputs-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | sensitiveOutputs = config.find_outputs_by_sensitivity(true) 26 | 27 | nonSensitiveOutputs = config.find_outputs_by_sensitivity(false) 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_outputs_in_module.md: -------------------------------------------------------------------------------- 1 | # find_outputs_in_module 2 | This function finds all outputs in a specific module in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_outputs_in_module = func(module_address)` 9 | 10 | ## Arguments 11 | * **module_address**: the address of the module containing outputs to find, given as a string. The root module is represented by "". A module named `network` called by the root module is represented by "module.network". if that module contained a module named `subnets`, it would be represented by "module.network.module.subnets". 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of outputs indexed by the address of the module and the name of the output. The map is actually a filtered sub-collection of the [`tfconfig.outputs`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-outputs-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | allRootModuleOutputs = config.find_outputs_in_module("") 26 | 27 | allNetworkOutputs = config.find_outputs_in_module("module.network") 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_providers_by_type.md: -------------------------------------------------------------------------------- 1 | # find_providers_by_type 2 | This function finds all providers of a specific type in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_providers_by_type = func(type)` 9 | 10 | ## Arguments 11 | * **type**: the type of provider to find, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of providers indexed by the address of the provider's module and the provider's name and alias. The map is actually a filtered sub-collection of the [`tfconfig.providers`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-providers-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | awsProviders = config.find_providers_by_type("aws") 26 | 27 | azureProviders = config.find_providers_by_type("azurerm") 28 | 29 | googleProviders = config.find_providers_by_type("google") 30 | 31 | vmwareProviders = config.find_providers_by_type("vsphere") 32 | ``` 33 | 34 | This function is used by the function `get_assumed_roles` in the [aws-functions](../../../aws/aws-functions/aws-functions.sentinel) module. 35 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_providers_in_module.md: -------------------------------------------------------------------------------- 1 | # find_providers_in_module 2 | This function finds all providers in a specific module in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_providers_in_module = func(module_address)` 9 | 10 | ## Arguments 11 | * **module_address**: the address of the module containing providers to find, given as a string. The root module is represented by "". A module named `network` called by the root module is represented by "module.network". if that module contained a module named `subnets`, it would be represented by "module.network.module.subnets". 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of providers indexed by the address of the provider's module and the provider's name and alias. The map is actually a filtered sub-collection of the [`tfconfig.providers`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-providers-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | allRootModuleProviders = config.find_providers_in_module("") 26 | 27 | allNetworkProviders = config.find_providers_in_module("module.network") 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_provisioners_by_type.md: -------------------------------------------------------------------------------- 1 | # find_provisioners_by_type 2 | This function finds all provisioners of a specific type in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_provisioners_by_type = func(type)` 9 | 10 | ## Arguments 11 | * **type**: the type of provisioner to find, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of provisioners indexed by the address of the resource the provisioner is attached to and the provisioner's own index within that resource's provisioners. The map is actually a filtered sub-collection of the [`tfconfig.provisioners`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-provisioners-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | remoteExecProvisioners = config.find_provisioners_by_type("remote-exec") 26 | 27 | localExecProvisioners = config.find_provisioners_by_type("local-exec") 28 | ``` 29 | 30 | This function is used by the cloud-agnostic [prevent-remote-exec-provisioners-on-null-resources.sentinel](../../../cloud-agnostic/prevent-remote-exec-provisioners-on-null-resources.sentinel) policy. 31 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_resources_by_provider.md: -------------------------------------------------------------------------------- 1 | # find_resources_by_provider 2 | This function finds all managed resources created by a specific provider in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_resources_by_provider = func(provider)` 9 | 10 | ## Arguments 11 | * **provider**: the provider of resources to find, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of resources indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources (excluding indices representing their counts). The map is actually a filtered sub-collection of the [`tfconfig.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-resources-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | allAWSResources = config.find_resources_by_provider("aws") 26 | 27 | allAzureResources = config.find_resources_by_provider("azurerm") 28 | 29 | allGoogleResources = config.find_resources_by_provider("google") 30 | 31 | allVMwareResources = config.find_resources_by_provider("vsphere") 32 | ``` 33 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_resources_by_type.md: -------------------------------------------------------------------------------- 1 | # find_resources_by_type 2 | This function finds all managed resources of a specific type in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_resources_by_type = func(type)` 9 | 10 | ## Arguments 11 | * **type**: the type of resource to find, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of resources indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources (excluding indices representing their counts). The map is actually a filtered sub-collection of the [`tfconfig.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-resources-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | allEC2Instances = config.find_resources_by_type("aws_instance") 26 | 27 | allAzureVMs = config.find_resources_by_type("azurerm_virtual_machine") 28 | 29 | allGCEInstances = config.find_resources_by_type("google_compute_instance") 30 | 31 | allVMs = config.find_resources_by_type("vsphere_virtual_machine") 32 | ``` 33 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_resources_in_module.md: -------------------------------------------------------------------------------- 1 | # find_resources_in_module 2 | This function finds all managed resources in a specific module in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_resources_in_module = func(module_address)` 9 | 10 | ## Arguments 11 | * **module_address**: the address of the module containing resources to find, given as a string. The root module is represented by "". A module named `network` called by the root module is represented by "module.network". if that module contained a module named `subnets`, it would be represented by "module.network.module.subnets". 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of resources indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources (excluding indices representing their counts). The map is actually a filtered sub-collection of the [`tfconfig.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-resources-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | allRootModuleResources = config.find_resources_in_module("") 26 | 27 | allNetworkResources = config.find_resources_in_module("module.network") 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/find_variables_in_module.md: -------------------------------------------------------------------------------- 1 | # find_variables_in_module 2 | This function finds all variables in a specific module in the Terraform configuration of the current plan's workspace using the [tfconfig/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_variables_in_module = func(module_address)` 9 | 10 | ## Arguments 11 | * **module_address**: the address of the module containing variables to find, given as a string. The root module is represented by "". A module named `network` called by the root module is represented by "module.network". if that module contained a module named `subnets`, it would be represented by "module.network.module.subnets". 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of variables indexed by the address of the module and the name of the variable. The map is actually a filtered sub-collection of the [`tfconfig.variables`](https://www.terraform.io/docs/cloud/sentinel/import/tfconfig-v2.html#the-variables-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 24 | ``` 25 | allRootModuleVariables = config.find_variables_in_module("") 26 | 27 | allNetworkVariables = config.find_variables_in_module("module.network") 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/print_violations.md: -------------------------------------------------------------------------------- 1 | # print_violations 2 | This function prints the violation messages that were previously returned by one of the filter functions of the tfconfig-functions.sentinel module. While those filter functions can print the violations messages themselves (if their `prtmsg` parameter is set to `true`), it is sometimes preferable to delay printing of the messages until later in the policy, typically after printing one or more messages giving the address of the resource that violated it. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `print_violations = func(messages, prefix)` 9 | 10 | ## Arguments 11 | * **messages**: a map of messages returned by one of the filter functions. 12 | * **prefix**: a string that should be printed before each message. 13 | 14 | ## Common Functions Used 15 | None 16 | 17 | ## What It Returns 18 | This function always returns `true`. 19 | 20 | ## What It Prints 21 | This function prints the messages in the `messages` map prefixed with the `prefix` string. 22 | 23 | ## Examples 24 | Here are some examples of calling this function, assuming that the tfconfig-functions.sentinel file that contains it has been imported with the alias `config`: 25 | ``` 26 | config.print_violations(violatingDatasources["messages"], "Blacklisted data source:") 27 | 28 | config.print_violations(violatingProviders["messages"], "Blacklisted provider:") 29 | ``` 30 | 31 | This function is used by many of the cloud agnostic policies including [prohibited-datasources.sentinel](../../../cloud-agnostic/prohibited-datasources.sentinel) and [prohibited-providers.sentinel](../../../cloud-agnostic/prohibited-providers.sentinel). 32 | -------------------------------------------------------------------------------- /common-functions/tfconfig-functions/docs/to_string.md: -------------------------------------------------------------------------------- 1 | # to_string 2 | This function converts any Sentinel object including complex compositions of primitive types (string, int, float, and bool), null, undefined, lists, and maps to a string. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfconfig-functions.sentinel](../../tfconfig-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `to_string = func(obj)` 9 | 10 | ## Arguments 11 | * **obj**: a Sentinel object of any type 12 | 13 | ## Common Functions Used 14 | This function calls itself recursively to support composite objects. 15 | 16 | ## What It Returns 17 | This function returns a single string. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | This function is called by all of the filter functions in the tfconfig-functions.sentinel module. Here is a typical example: 24 | ``` 25 | message = to_string(index) + " has " + to_string(attr) + " with value " + 26 | to_string(val) + " that is not in the allowed list: " + 27 | to_string(allowed) 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/evaluate_attribute.md: -------------------------------------------------------------------------------- 1 | # evaluate_attribute 2 | This function evaluates the value of an attribute within a resource, data source, or block. The attribute can be deeply nested. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `evaluate_attribute = func(r, attribute)` 9 | 10 | ## Arguments 11 | * **r**: a single resource or block containing an attribute whose value you want to determine. 12 | * **attribute**: a string giving the attribute. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. If `r` represents a block, then `attribute` should be specified relative to that block. 13 | 14 | In practice, this function is only called by the filter functions, so the specification of the `attribute` parameter will be done when calling them. 15 | 16 | ## Common Functions Used 17 | This function calls itself recursively to support nested attributes of resources and blocks. 18 | 19 | ## What It Returns 20 | This function returns the value of the attribute of the resource or block. The type will vary depending on what kind of attribute is evaluated. 21 | 22 | ## What It Prints 23 | This function does not print anything. 24 | 25 | ## Examples 26 | This function is called by all of the filter functions in the tfplan-functions.sentinel module. Here is a typical example: 27 | ``` 28 | v = evaluate_attribute(rc, attr) else null 29 | ``` 30 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_contains_items_from_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_contains_items_from_list 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that contains any members of a given list. A policy would call it when it does not want the attribute to contain any members of the list. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_contains_items_from_list = func(resources, attr, forbidden, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should not contain any items in a given list. The attribute should be a list or a map. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params` rather than `boot_disk[0].initialize_params`. 13 | * **forbidden**: a list of values the attribute should not contain. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) contains any items of the list (`forbidden`) while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here is an example of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 27 | ``` 28 | violatingSGRules = plan.filter_attribute_contains_items_from_list(SGIngressRules, 29 | "cidr_blocks",forbidden_cidrs, true) 30 | ``` 31 | 32 | This function is used by the [restrict-ingress-sg-rule-cidr-blocks.sentinel (AWS)](../../../aws/restrict-ingress-sg-rule-cidr-blocks.sentinel) policy. 33 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_contains_items_not_in_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_contains_items_not_in_list 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that contains any items that are not in a given list. A policy would call it when it wants the attribute to only contain members of the list (but not necessarily all of them). 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_contains_items_not_in_list = func(resources, attr, allowed, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should should only contain items from a given list. The attribute should be a list or a map. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params` rather than `boot_disk[0].initialize_params`. 13 | * **allowed**: a list of values the attribute is allowed to contain. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) contains any items that are not in the list (`allowed`) while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here is an example of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 27 | ``` 28 | violatingIRs = plan.filter_attribute_contains_items_not_in_list(ingressRules, 29 | "cidr_blocks", allowed_cidrs, false) 30 | ``` 31 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_does_not_have_prefix.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_does_not_have_prefix 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that does have a specified prefix. A policy would call it when it wants the attribute to start with that prefix. 3 | 4 | It uses Sentinel's standard [strings](https://docs.hashicorp.com/sentinel/imports/strings/) import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_does_not_have_prefix = func(resources, attr, prefix, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should start with the given prefix. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **prefix**: the prefix that the attribute should start with. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) does not start with `prefix`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 29 | ``` 30 | violatingAccessKeys = plan.filter_attribute_does_not_have_prefix(allAccessKeys, 31 | "pgp_key", "keybase:", true) 32 | 33 | violatingEC2Instances = plan.filter_attribute_does_not_have_prefix( 34 | allEC2Instances, "instance_type", "m5.", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_does_not_have_suffix.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_does_not_have_suffix 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that does have a specified suffix. A policy would call it when it wants the attribute to end with that suffix. 3 | 4 | It uses Sentinel's standard [strings](https://docs.hashicorp.com/sentinel/imports/strings/) import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_does_not_have_suffix = func(resources, attr, suffix, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should end with the given suffix. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **suffix**: the suffix that the attribute should end with. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) does not end with `suffix`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 29 | ``` 30 | violatingS3Buckets = plan.filter_attribute_does_not_have_suffix(allS3Buckets, 31 | "acl", "-full-control", true) 32 | 33 | violatingGCESubnets = plan.filter_attribute_does_not_have_suffix( 34 | allGCESubnets, "ip_cidr_range", "/24", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_does_not_match_regex.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_does_not_match_regex 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that does not match a given regular expression (regex). A policy would call it when it wants the attribute to match that regex. 3 | 4 | It uses the Sentinel [matches](https://docs.hashicorp.com/sentinel/language/spec/#matches-operator) operator which uses [RE2](https://github.com/google/re2/wiki/Syntax) regex. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_does_not_match_regex = func(resources, attr, expr, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should match the given regex. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **expr**: the regex expression that should be matched. Note that any occurrences of `\` need to be escaped with `\` itself since Sentinel allows certain special characters to be escaped with `\`. For example, if you wanted to match sub-domains of ".acme.com", you would set `expr` to `(.+)\\.acme\\.com$` instead of the more usual `(.+)\.acme\.com$`. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) does not match the given regex, `expr`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 29 | ``` 30 | violatingACMCerts = plan.filter_attribute_does_not_match_regex(allACMCerts, 31 | "domain_name", "(.+)\\.hashidemos\\.io$", true) 32 | 33 | violatingAccessKeys = plan.filter_attribute_does_not_match_regex(allAccessKeys, 34 | "pgp_key", "^keybase:(.+)", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_greater_than_value.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_greater_than_value 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that is greater than a given numeric value. A policy would call it when it wants the attribute to be less than or equal to the given value. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_greater_than_value = func(resources, attr, value, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should be less than or equal to a given value. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **value**: the value the attribute should be less than or equal to. This should be an integer or a float. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is greater than the given value, `value`, while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 27 | ``` 28 | highCPUVMs = plan.filter_attribute_greater_than_value(allVMs, 29 | "num_cpus", maxCPUs, true) 30 | 31 | 32 | highMemoryVMs = plan.filter_attribute_greater_than_value(allVMs, 33 | "memory", maxMemory, true) 34 | 35 | violatingDisks = plan.filter_attribute_greater_than_value(disks, 36 | "size", maxDiskSize, false) 37 | ``` 38 | 39 | This function is used by the policies [restrict-vm-cpu-and-memory.sentinel (VMware)](../../../vmware/restrict-vm-cpu-and-memory.sentinel), [restrict-vm-disk-size.sentinel (VMware)](../../../vmware/restrict-vm-disk-size.sentinel) 40 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_has_prefix.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_has_prefix 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that has a specified prefix. A policy would call it when it wants the attribute to not start with that prefix. 3 | 4 | It uses Sentinel's standard [strings](https://docs.hashicorp.com/sentinel/imports/strings/) import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_has_prefix = func(resources, attr, prefix, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should not start with the given prefix. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **prefix**: the prefix that the attribute should not start with. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) starts with `prefix`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 29 | ``` 30 | violatingAccessKeys = plan.filter_attribute_has_prefix(allAccessKeys, 31 | "pgp_key", "keybase:", true) 32 | 33 | violatingAzureVMs = plan.filter_attribute_has_prefix( 34 | allAzureVMs, "vm_size", "Standard_", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_has_suffix.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_has_suffix 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that has a specified suffix. A policy would call it when it wants the attribute to not end with that suffix. 3 | 4 | It uses Sentinel's standard [strings](https://docs.hashicorp.com/sentinel/imports/strings/) import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_has_suffix = func(resources, attr, suffix, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should not end with the given suffix. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **suffix**: the suffix that the attribute should not end with. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) ends with `suffix`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 29 | ``` 30 | violatingS3Buckets = plan.filter_attribute_has_suffix(allS3Buckets, 31 | "acl", "-full-control", true) 32 | 33 | violatingGCESubnets = plan.filter_attribute_has_suffix( 34 | allGCESubnets, "ip_cidr_range", "/8", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_in_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_in_list 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute contained in a provided list. A policy would call it when it does not want the attribute set to any member of the list. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_in_list = func(resources, attr, forbidden, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that must not be in a given list. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **forbidden**: a list of values the attribute is forbidden to have. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is in in the list (`forbidden`) while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 27 | ``` 28 | violatingEC2Instances = plan.filter_attribute_in_list(allEC2Instances, 29 | "instance_type", forbidden_types, true) 30 | 31 | violatingAzureVMs = plan.filter_attribute_in_list(allAzureVMs, 32 | "vm_size", forbidden_sizes, true) 33 | 34 | violatingGCEInstances = plan.filter_attribute_in_list(allGCEInstances, 35 | "machine_type", forbidden_types, true) 36 | ``` 37 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_is_not_value.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_is_not_value 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that is not equal to a given value. A policy would call it when it wants the attribute to equal the given value. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_is_not_value = func(resources, attr, value, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should equal a given value. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **value**: the value the attribute should have. This can be any primitive data type. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is not equal to the given value, `value`, while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 27 | ``` 28 | nonPrivateS3Buckets = plan.filter_attribute_is_not_value(allS3Buckets, 29 | "acl", "private", true) 30 | 31 | nonEncryptedS3Buckets = plan.filter_attribute_is_not_value(allS3Buckets, 32 | "server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm", 33 | "aws:kms", true) 34 | 35 | violatingAzureAppServices = plan.filter_attribute_is_not_value(allAzureAppServices, 36 | "https_only", true, true) 37 | ``` 38 | 39 | This function is used by the [require-private-acl-and-kms-for-s3-buckets.sentinel (AWS)](../../../aws/require-private-acl-and-kms-for-s3-buckets.sentinel) and [restrict-app-service-to-https.sentinel (Azure)](../../../azure/restrict-app-service-to-https.sentinel) policies. 40 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_is_value.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_is_value 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that is equal to a given value. A policy would call it when it wants the attribute to not equal the given value. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_is_value = func(resources, attr, value, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should not equal a given value. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **value**: the value the attribute should not have. This can be any primitive data type. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is equal to the given value, `value`, while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 27 | ``` 28 | nonPrivateS3Buckets = plan.filter_attribute_is_value(allS3Buckets, 29 | "acl", "public_read", true) 30 | 31 | 32 | violatingAzureAppServices = plan.filter_attribute_is_value(allAzureAppServices, 33 | "https_only", false, true) 34 | ``` 35 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_less_than_value.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_less_than_value 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that is less than a given numeric value. A policy would call it when it wants the attribute to be greater than or equal to the given value. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_less_than_value = func(resources, attr, value, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should be greater than or equal to a given value. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **value**: the value the attribute should be greater than or equal to. This should be an integer or a float. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is less than the given value, `value`, while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 27 | ``` 28 | lowCPUVMs = plan.filter_attribute_less_than_value(allVMs, 29 | "num_cpus", minCPUs, true) 30 | 31 | 32 | lowMemoryVMs = plan.filter_attribute_less_than_value(allVMs, 33 | "memory", minMemory, true) 34 | ``` 35 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_matches_regex.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_matches_regex 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that matches a given regular expression (regex). A policy would call it when it wants the attribute to not match that regex. 3 | 4 | It uses the Sentinel [matches](https://docs.hashicorp.com/sentinel/language/spec/#matches-operator) operator which uses [RE2](https://github.com/google/re2/wiki/Syntax) regex. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_matches_regex = func(resources, attr, expr, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should match the given regex. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **expr**: the regex expression that should be matched. Note that any occurrences of `\` need to be escaped with `\` itself since Sentinel allows certain special characters to be escaped with `\`. For example, if you did not want to match sub-domains of ".acme.com", you would set `expr` to `(.+)\\.acme\\.com$` instead of the more usual `(.+)\.acme\.com$`. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) matches the given regex, `expr`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 29 | ``` 30 | violatingACMCerts = plan.filter_attribute_matches_regex(allACMCerts, 31 | "domain_name", "(.+)\\.hashidemos\\.io$", true) 32 | 33 | violatingAccessKeys = plan.filter_attribute_matches_regex(allAccessKeys, 34 | "pgp_key", "^keybase:(.+)", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_not_contains_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_not_contains_list 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that does not contain all members of a given list. A policy would call it when it wants the attribute to contain all members of the list. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_not_contains_list = func(resources, attr, required, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that must contain all items from a given list. The attribute should be a list or map. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params` rather than `boot_disk[0].initialize_params`. 13 | * **required**: a list of values all of which the attribute should contain. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) does not contain all items of the list (`required`) while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 27 | ``` 28 | violatingEC2Instances = plan.filter_attribute_not_contains_list(allEC2Instances, 29 | "tags", mandatory_tags, true) 30 | 31 | violatingAzureVMs = plan.filter_attribute_not_contains_list(allAzureVMs, 32 | "tags", mandatory_tags, true) 33 | 34 | violatingGCEInstances = plan.filter_attribute_not_contains_list(allGCEInstances, 35 | "labels", mandatory_labels, true) 36 | ``` 37 | 38 | This function is used by several policies including [enforce-mandatory-tags.sentinel (AWS)](../../../aws/enforce-mandatory-tags.sentinel), [enforce-mandatory-tags.sentinel (Azure)](../../../azure/enforce-mandatory-tags.sentinel), and [enforce-mandatory-labels.sentinel (GCP)](../../../gcp/enforce-mandatory-labels.sentinel). 39 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/filter_attribute_not_in_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_not_in_list 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that is not contained in a provided list. A policy would call it when it wants the attribute to have a value from the list. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_not_in_list = func(resources, attr, allowed, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that must be in a given list. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **allowed**: a list of values the attribute is allowed to have. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is not in the list (`allowed`) while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 27 | ``` 28 | violatingEC2Instances = plan.filter_attribute_not_in_list(allEC2Instances, 29 | "instance_type", allowed_types, true) 30 | 31 | violatingAzureVMs = plan.filter_attribute_not_in_list(allAzureVMs, 32 | "vm_size", allowed_sizes, true) 33 | 34 | violatingGCEInstances = plan.filter_attribute_not_in_list(allGCEInstances, 35 | "machine_type", allowed_types, true) 36 | ``` 37 | 38 | This function is used by many policies including [restrict-ec2-instance-type.sentinel (AWS)](../../../aws/restrict-ec2-instance-type.sentinel), [restrict-vm-size.sentinel (Azure)](../../../azure/restrict-vm-size.sentinel), and [restrict-gce-machine-type.sentinel (GCP)](../../../gcp/restrict-gce-machine-type.sentinel). 39 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/find_blocks.md: -------------------------------------------------------------------------------- 1 | # find_blocks 2 | This function finds all blocks of a specific type under a single resource or block in the current plan using the [tfplan/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_blocks = func(parent, child)` 9 | 10 | ## Arguments 11 | * **parent**: a single resource or block of a resource 12 | * **child**: a string representing the child blocks to be found in the parent. 13 | 14 | ## Common Functions Used 15 | None 16 | 17 | ## What It Returns 18 | This function returns a single list of child blocks found in the parent resource or block. Each child block is represented by a map. 19 | 20 | ## What It Prints 21 | This function does not print anything. 22 | 23 | ## Examples 24 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 25 | ``` 26 | ingressRules = plan.find_blocks(sg, "ingress") 27 | 28 | disks = plan.find_blocks(vm, "disk") 29 | ``` 30 | 31 | This function is used by the [restrict-ingress-sg-rule-cidr-blocks.sentinel (AWSc)](../../../aws/restrict-ingress-sg-rule-cidr-blocks.sentinel) and [restrict-vm-disk-size.sentinel (VMware)](../../../vmware/restrict-vm-disk-size.sentinel) policies. 32 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/find_datasources.md: -------------------------------------------------------------------------------- 1 | # find_datasources 2 | This function finds all data source instances of a specific type that are being created, modified, or read in the current plan using the [tfplan/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html) import. 3 | 4 | When evaluating data sources that do not reference any computed values (those known after doing an apply), it is usually better to use the [tfstate/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html) import and the corresponding [find_datasources](../tfstate-functions/find_datasources.md) function that uses that import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) Sentinel module. 8 | 9 | ## Declaration 10 | `find_datasources = func(type)` 11 | 12 | ## Arguments 13 | * **type**: the type of datasource to find, given as a string. 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of data source instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 26 | ``` 27 | allAMIs = plan.find_datasources("aws_ami") 28 | 29 | allImages = plan.find_datasources("azurerm_image") 30 | 31 | allImages = plan.find_datasources("google_compute_image") 32 | 33 | allDatastores = plan.find_datasources("vsphere_datastore") 34 | ``` 35 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/find_datasources_being_destroyed.md: -------------------------------------------------------------------------------- 1 | # find_datasources_being_destroyed 2 | This function finds all data source instances being destroyed but not re-created in the current plan using the [tfplan/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_datasources_being_destroyed = func()` 9 | 10 | ## Arguments 11 | None 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of data source instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/data source-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfplan.data source_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-data source_changes-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here is an example of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 24 | ``` 25 | datasourcesBeingDestroyed = plan.find_data sources_being_destroyed() 26 | ``` 27 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/find_datasources_by_provider.md: -------------------------------------------------------------------------------- 1 | # find_datasources_by_provider 2 | This function finds all data source instances for a specific provider that are being created, modified, or read in the current plan using the [tfplan/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html) import. 3 | 4 | When evaluating data sources that do not reference any computed values (those known after doing an apply), it is usually better to use the [tfstate/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html) import and the corresponding [find_datasources](../tfstate-functions/find_datasources.md) function that uses that import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) Sentinel module. 8 | 9 | ## Declaration 10 | `find_datasources_by_provider = func(provider)` 11 | 12 | ## Arguments 13 | * **provider**: the provider, given as a string. 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns a single flat map of data source instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) collection. 20 | 21 | ## What It Prints 22 | This function does not print anything. 23 | 24 | ## Examples 25 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 26 | ``` 27 | allAWSDataSources = plan.find_datasources_by_provider("aws") 28 | 29 | allAzureDataSources = plan.find_datasources_by_provider("azurerm") 30 | 31 | allGCPDataSources = plan.find_datasources_by_provider("google") 32 | 33 | allVMwareDataSources = plan.find_datasources("vsphere") 34 | ``` 35 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/find_resources.md: -------------------------------------------------------------------------------- 1 | # find_resources 2 | This function finds all resource instances of a specific type in the current plan that are being created or modified using the [tfplan/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_resources = func(type)` 9 | 10 | ## Arguments 11 | * **type**: the type of resource to find, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of resource instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 24 | ``` 25 | allEC2Instances = plan.find_resources("aws_instance") 26 | 27 | allAzureVMs = plan.find_resources("azurerm_virtual_machine") 28 | 29 | allGCEInstances = plan.find_resources("google_compute_instance") 30 | 31 | allVMs = plan.find_resources("vsphere_virtual_machine") 32 | ``` 33 | 34 | This function is used by many policies including [restrict-ec2-instance-type.sentinel (AWS)](../../../aws/restrict-ec2-instance-type.sentinel), [restrict-vm-size..sentinel (Azure)](../../../azure/restrict-vm-size..sentinel), [restrict-gce-machine-type.sentinel (GCP)](../../../gcp/restrict-gce-machine-type.sentinel), and [restrict-vm-cpu-and-memory.sentinel (VMware)](../../../vmware/restrict-vm-cpu-and-memory.sentinel). 35 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/find_resources_being_destroyed.md: -------------------------------------------------------------------------------- 1 | # find_resources_being_destroyed 2 | This function finds all resource instances being destroyed but not re-created in the current plan using the [tfplan/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_resources_being_destroyed = func()` 9 | 10 | ## Arguments 11 | None 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of resource instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here is an example of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 24 | ``` 25 | resourcesBeingDestroyed = plan.find_resources_being_destroyed() 26 | ``` 27 | 28 | This function is used by the [prevent-destruction-of-prohibited-resources.sentinel (Cloud Agnostic)](../../../cloud-agnostic/prevent-destruction-of-prohibited-resources.sentinel) policy. 29 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/find_resources_by_provider.md: -------------------------------------------------------------------------------- 1 | # find_resources_by_provider 2 | This function finds all resource instances for a specific provider in the current plan that are being created or modified using the [tfplan/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_resources_by_provider = func(provider)` 9 | 10 | ## Arguments 11 | * **provider**: the provider, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of resource instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfplan.resource_changes`](https://www.terraform.io/docs/cloud/sentinel/import/tfplan-v2.html#the-resource_changes-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 24 | ``` 25 | allAWSResources = plan.find_resources_by_provider("aws") 26 | 27 | allAzureResources = plan.find_resources_by_provider("azurerm") 28 | 29 | allGCPResources = plan.find_resources_by_provider("google") 30 | 31 | allVMwareResources = plan.find_resources_by_provider("vsphere") 32 | ``` 33 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/print_violations.md: -------------------------------------------------------------------------------- 1 | # print_violations 2 | This function prints the violation messages that were previously returned by one of the filter functions of the tfplan-functions.sentinel module. While those filter functions can print the violations messages themselves (if their `prtmsg` parameter is set to `true`), it is sometimes preferable to delay printing of the messages until later in the policy, typically after printing one or more messages giving the address of the resource that violated it. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `print_violations = func(messages, prefix)` 9 | 10 | ## Arguments 11 | * **messages**: a map of messages returned by one of the filter functions. 12 | * **prefix**: a string that should be printed before each message. 13 | 14 | ## Common Functions Used 15 | None 16 | 17 | ## What It Returns 18 | This function always returns `true`. 19 | 20 | ## What It Prints 21 | This function prints the messages in the `messages` map prefixed with the `prefix` string. 22 | 23 | ## Examples 24 | Here are some examples of calling this function, assuming that the tfplan-functions.sentinel file that contains it has been imported with the alias `plan`: 25 | ``` 26 | if length(violatingIRs["messages"]) > 0 { 27 | violatingSGsCount += 1 28 | print("SG Ingress Violation:", address, "has at least one ingress rule", 29 | "with forbidden cidr blocks") 30 | plan.print_violations(violatingIRs["messages"], "Ingress Rule") 31 | } 32 | 33 | if length(violatingDisks["messages"]) > 0 { 34 | disksValidated = false 35 | print(address, "has at least one disk with size greater than", maxDiskSize) 36 | plan.print_violations(violatingDisks["messages"], "Disk") 37 | } 38 | ``` 39 | 40 | This function is used by the [restrict-ingress-sg-rule-cidr-blocks.sentinel (AWS)](../../../aws/restrict-ingress-sg-rule-cidr-blocks.sentinel) and [restrict-vm-disk-size.sentinel (VMware)](../../../vmware/restrict-vm-disk-size.sentinel). 41 | -------------------------------------------------------------------------------- /common-functions/tfplan-functions/docs/to_string.md: -------------------------------------------------------------------------------- 1 | # to_string 2 | This function converts any Sentinel object including complex compositions of primitive types (string, int, float, and bool), null, undefined, lists, and maps to a string. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfplan-functions.sentinel](../tfplan-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `to_string = func(obj)` 9 | 10 | ## Arguments 11 | * **obj**: a Sentinel object of any type 12 | 13 | ## Common Functions Used 14 | This function calls itself recursively to support composite objects. 15 | 16 | ## What It Returns 17 | This function returns a single string. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | This function is called by all of the filter functions in the tfplan-functions.sentinel module. Here is a typical example: 24 | ``` 25 | message = to_string(address) + " has " + to_string(attr) + " with value " + 26 | to_string(v) + " that is not in the allowed list: " + 27 | to_string(allowed) 28 | ``` 29 | -------------------------------------------------------------------------------- /common-functions/tfrun-functions/docs/limit_cost_and_percentage_increase.md: -------------------------------------------------------------------------------- 1 | # limit_cost_and_percentage_increase 2 | This function validates that the proposed monthly cost from the [cost estimates](https://www.terraform.io/docs/cloud/cost-estimation/index.html) of a plan done against a workspace is less than a given limit which is given in US dollars and that the percentage increase of the monthly cost is less than a given maximum percentage. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfrun-functions.sentinel](../tfrun-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `limit_cost_and_percentage_increase = func(limit, max_percent)` 9 | 10 | ## Arguments 11 | * **limit**: the upper limit on the allowed estimated monthly costs (in US dollars) for the resources provisioned in the workspace, given as a [decimal](https://docs.hashicorp.com/sentinel/imports/decimal/). 12 | * **max_percent**: the upper limit on the percentage increase of the estimated monthly costs compared to the current monthly cost (if available), also given as a decimal. 13 | 14 | ## Common Functions Used 15 | None 16 | 17 | ## What It Returns 18 | This function returns `true` if the estimated monthly costs of the workspace are under `limit` and the percentage increase of those costs is less than `max_percent` or if no cost estimates were available. Otherwise, it returns `false`. 19 | 20 | ## What It Prints 21 | This function prints messages indicating whether or not the estimated monthly costs are allowed or not. Additionally, if no cost estimates are available, it prints a message to indicate that. 22 | 23 | ## Examples 24 | Here is an example of calling this function, assuming that the tfrun-functions.sentinel file that contains it has been imported with the alias `run`: 25 | ``` 26 | limit = decimal.new(1000) 27 | max_percent = decimal.new(10.0) 28 | cost_validated = run.limit_cost_and_percentage_increase(limit, max_percent) 29 | ``` 30 | Note that any policy calling this function must also import the standard decimal import with `import "decimal"`. 31 | 32 | This function is used by the cloud agnostic policy [limit-cost-and-percentage-increase.sentinel](../../../cloud-agnostic/limit-cost-and-percentage-increase.sentinel). 33 | -------------------------------------------------------------------------------- /common-functions/tfrun-functions/docs/limit_cost_by_workspace_name.md: -------------------------------------------------------------------------------- 1 | # limit_cost_by_workspace_name 2 | This function validates that the proposed monthly cost from the [cost estimates](https://www.terraform.io/docs/cloud/cost-estimation/index.html) of a plan done against a workspace is less than a given limit (given in US dollars). The limit is determined from a map that associates workspace names with different limits using regex matching. 3 | 4 | The idea is that you might set different limits for Dev, QA, and Production workspaces. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfrun-functions.sentinel](../tfrun-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `limit_cost_by_workspace_name = func(limits)` 11 | 12 | ## Arguments 13 | * **limits**: a map associating strings (the keys of the map) with different upper limits (the values of the map) for the allowed estimated monthly costs (in US dollars) for the resources provisioned in the workspace. The strings are treated as workspace name prefixes and suffixes. In other words, the limit associated with the string "dev" will be applied to workspaces whose names start with "dev-" or end with "-dev". The limits assigned to each string in the map must be given as [decimals](https://docs.hashicorp.com/sentinel/imports/decimal/). Of course, you must coordinate the naming of your workspaces with the keys of the `limits` map. 14 | 15 | ## Common Functions Used 16 | None 17 | 18 | ## What It Returns 19 | This function returns `true` if the estimated monthly cost of the workspace is under the limit in the `limits` map that corresponds to the workspace name or if no cost estimates were available. Otherwise, it returns `false`. Note that if a workspace name does not match any of the keys in the `limits` map, the function will return `false` and probably cause the policy that called it to fail. 20 | 21 | ## What It Prints 22 | This function prints messages indicating whether or not the estimated monthly costs are under the limit in the `limits` map that corresponds to the workspace name. Additionally, if no cost estimates are available or if the `limits` map does not contain a key that matches the workspace name, it prints a message to indicate that. 23 | 24 | ## Examples 25 | Here is an example of calling this function, assuming that the tfrun-functions.sentinel file that contains it has been imported with the alias `run`: 26 | ``` 27 | limits = { 28 | "dev": decimal.new(200), 29 | "qa": decimal.new(500), 30 | "prod": decimal.new(1000), 31 | } 32 | cost_validated = run.limit_cost_by_workspace_name(limits) 33 | ``` 34 | Note that any policy calling this function must also import the standard decimal import with `import "decimal"`. 35 | 36 | This function is used by the cloud agnostic policy [limit-cost-by-workspace-name.sentinel](../../../cloud-agnostic/limit-cost-by-workspace-name.sentinel). 37 | -------------------------------------------------------------------------------- /common-functions/tfrun-functions/docs/limit_proposed_monthly_cost.md: -------------------------------------------------------------------------------- 1 | # limit_proposed_monthly_cost 2 | This function validates that the proposed monthly cost from the [cost estimates](https://www.terraform.io/docs/cloud/cost-estimation/index.html) of a plan done against a workspace is less than a given limit which is given in US dollars. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfrun-functions.sentinel](../tfrun-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `limit_proposed_monthly_cost = func(limit)` 9 | 10 | ## Arguments 11 | * **limit**: the upper limit on the allowed estimated monthly cost (in US dollars) for the resources provisioned in the workspace, given as a [decimal](https://docs.hashicorp.com/sentinel/imports/decimal/). 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns `true` if the estimated monthly cost of the workspace is less than or equal to `limit` or if no cost estimates were available. Otherwise, it returns `false`. 18 | 19 | ## What It Prints 20 | This function prints messages indicating whether or not the estimated monthly cost is less than or equal to the limit. Additionally, if no cost estimates are available, it prints a message to indicate that. 21 | 22 | ## Examples 23 | Here is an example of calling this function, assuming that the tfrun-functions.sentinel file that contains it has been imported with the alias `run`: 24 | ``` 25 | limit = decimal.new(1000) 26 | cost_validated = run.limit_proposed_monthly_cost(limit) 27 | ``` 28 | Note that any policy calling this function must also import the standard decimal import with `import "decimal"`. 29 | 30 | This function is used by the cloud agnostic policy [limit-proposed-monthly-cost.sentinel](../../../cloud-agnostic/limit-proposed-monthly-cost.sentinel). 31 | -------------------------------------------------------------------------------- /common-functions/tfrun-functions/tfrun-functions.sentinel: -------------------------------------------------------------------------------- 1 | # Common functions that use the tfrun import 2 | 3 | ##### Imports ##### 4 | import "tfrun" 5 | import "decimal" 6 | 7 | ##### Functions ##### 8 | 9 | ### limit_proposed_monthly_cost ### 10 | # Validate that the proposed monthly cost is less than the limit 11 | limit_proposed_monthly_cost = func(limit) { 12 | 13 | # Check whether cost estimate is available 14 | # It should be for Terraform 0.12.x 15 | # It should not be for Terraform 0.11.x 16 | if tfrun.cost_estimate else null is null { 17 | print("No cost estimates available") 18 | # Allow the policy to pass 19 | return true 20 | } 21 | 22 | # Determine proposed monthly cost 23 | proposed_cost = decimal.new(tfrun.cost_estimate.proposed_monthly_cost) 24 | 25 | # Compare proposed monthly cost to the limit 26 | if proposed_cost.lte(limit) { 27 | print("Proposed monthly cost", proposed_cost.string, 28 | "is under the limit:", limit.string) 29 | return true 30 | } else { 31 | print("Proposed monthly cost", proposed_cost.string, 32 | "is over the limit:", limit.string) 33 | return false 34 | } 35 | } 36 | 37 | ### limit_cost_and_percentage_increase ### 38 | # Validate that the proposed cost is less than the given limit and 39 | # that the percentage increase in the monthly cost 40 | # is less than a given percentage 41 | limit_cost_and_percentage_increase = func(limit, max_percent) { 42 | 43 | validated = true 44 | 45 | # Check whether cost estimate is available 46 | # It should be for Terraform 0.12.x 47 | # It should not be for Terraform 0.11.x 48 | if tfrun.cost_estimate else null is null { 49 | print("No cost estimates available") 50 | # Allow the policy to pass 51 | return true 52 | } 53 | 54 | # Determine cost data 55 | prior_cost = decimal.new(tfrun.cost_estimate.prior_monthly_cost) 56 | proposed_cost = decimal.new(tfrun.cost_estimate.proposed_monthly_cost) 57 | increase_in_cost = decimal.new(tfrun.cost_estimate.delta_monthly_cost) 58 | 59 | # Compare proposed monthly cost to the limit 60 | if proposed_cost.gt(limit) { 61 | print("Proposed monthly cost", proposed_cost.string, 62 | "is over the limit:", limit.string) 63 | validated = false 64 | } 65 | 66 | # If prior_cost is not 0.0, compare percentage increase in monthly cost 67 | # to max_percent 68 | if prior_cost.is_not(0.0) { 69 | percentage_change = increase_in_cost.divide(prior_cost).multiply(100) 70 | if decimal.new(percentage_change).gt(max_percent) { 71 | print("Proposed percentage increase", percentage_change.float, 72 | "is over the max percentage change:", max_percent.float) 73 | validated = false 74 | } else { 75 | print("Proposed percentage increase", percentage_change.float, 76 | "is under the max percentage change:", max_percent.float) 77 | } 78 | } 79 | 80 | return validated 81 | 82 | } 83 | 84 | ### limit_cost_by_workspace_name ### 85 | # Validate that the proposed monthly cost is less than the limit 86 | # This accepts a map, limits, whose keys should be strings like 87 | # "dev", "qa", or "prod" and whose values should be expressions like 88 | # decimal.new(200) (which indicates a monthly limit of $200). 89 | # The keys are treated as allowed workspace name prefixes and suffixes. 90 | # If a workspace does not have one of the keys as a prefix or suffix, it will 91 | # fail the policy. 92 | limit_cost_by_workspace_name = func(limits) { 93 | 94 | # Check whether cost estimate is available 95 | # It should be for Terraform 0.12.x 96 | # It should not be for Terraform 0.11.x 97 | if tfrun.cost_estimate else null is null { 98 | print("No cost estimates available") 99 | # Allow the policy to pass 100 | return true 101 | } 102 | 103 | # Get workspace name 104 | workspace_name = tfrun.workspace.name 105 | 106 | # Iterate over the limits map to determine limit 107 | the_limit = decimal.new(0) 108 | matching_name_found = false 109 | for limits as name, limit { 110 | if workspace_name matches "(.+)-" + name + "$" or 111 | workspace_name matches "^" + name + "-(.+)$" { 112 | the_limit = limits[name] 113 | matching_name_found = true 114 | break 115 | } 116 | } 117 | 118 | # Print message if workspace name did not match any keys 119 | if matching_name_found is false { 120 | print("The current workspace", workspace_name, 121 | "is not allowed because no cost limits are associated with a", 122 | "regular expression matching its name.") 123 | return false 124 | } 125 | 126 | # Determine proposed monthly cost 127 | proposed_cost = decimal.new(tfrun.cost_estimate.proposed_monthly_cost) 128 | 129 | # Compare proposed monthly cost to the limit 130 | if proposed_cost.lte(the_limit) { 131 | print("Proposed monthly cost", proposed_cost.string, 132 | "of workspace", workspace_name, 133 | "is under the limit:", the_limit.string) 134 | return true 135 | } else { 136 | print("Proposed monthly cost", proposed_cost.string, 137 | "of workspace", workspace_name, 138 | "is over the limit:", the_limit.string) 139 | return false 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/evaluate_attribute.md: -------------------------------------------------------------------------------- 1 | # evaluate_attribute 2 | This function evaluates the value of an attribute within a resource, data source, or block. The attribute can be deeply nested. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `evaluate_attribute = func(r, attribute)` 9 | 10 | ## Arguments 11 | * **r**: a single resource or block containing an attribute whose value you want to determine. 12 | * **attribute**: a string giving the attribute. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. If `r` represents a block, then `attribute` should be specified relative to that block. 13 | 14 | In practice, this function is only called by the filter functions, so the specification of the `attribute` parameter will be done when calling them. 15 | 16 | ## Common Functions Used 17 | This function calls itself recursively to support nested attributes of resources and blocks. 18 | 19 | ## What It Returns 20 | This function returns the value of the attribute of the resource or block. The type will vary depending on what kind of attribute is evaluated. 21 | 22 | ## What It Prints 23 | This function does not print anything. 24 | 25 | ## Examples 26 | This function is called by all of the filter functions in the tfstate-functions.sentinel module. Here is a typical example: 27 | ``` 28 | v = evaluate_attribute(r, attr) else null 29 | ``` 30 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_contains_items_from_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_contains_items_from_list 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that contains any members of a given list. A policy would call it when it does not want the attribute to contain any members of the list. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_contains_items_from_list = func(resources, attr, forbidden, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should not contain any items in a given list. The attribute should be a list or a map. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params` rather than `boot_disk[0].initialize_params`. 13 | * **forbidden**: a list of values the attribute should not contain. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) contains any items of the list (`forbidden`) while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here is an example of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 27 | ``` 28 | violatingSGRules = state.filter_attribute_contains_items_from_list(SGIngressRules, 29 | "cidr_blocks",forbidden_cidrs, true) 30 | ``` 31 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_contains_items_not_in_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_contains_items_not_in_list 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that contains any items that are not in a given list. A policy would call it when it wants the attribute to only contain members of the list (but not necessarily all of them). 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_contains_items_not_in_list = func(resources, attr, allowed, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should should only contain items from a given list. The attribute should be a list or a map. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params` rather than `boot_disk[0].initialize_params`. 13 | * **allowed**: a list of values the attribute is allowed to contain. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) contains any items that are not in the list (`allowed`) while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here is an example of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 27 | ``` 28 | violatingIRs = state.filter_attribute_contains_items_not_in_list(ingressRules, 29 | "cidr_blocks", allowed_cidrs, false) 30 | ``` 31 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_does_not_have_prefix.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_does_not_have_prefix 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that does have a specified prefix. A policy would call it when it wants the attribute to start with that prefix. 3 | 4 | It uses Sentinel's standard [strings](https://docs.hashicorp.com/sentinel/imports/strings/) import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_does_not_have_prefix = func(resources, attr, prefix, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should start with the given prefix. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **prefix**: the prefix that the attribute should start with. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) does not start with `prefix`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 29 | ``` 30 | violatingAccessKeys = state.filter_attribute_does_not_have_prefix(allAccessKeys, 31 | "pgp_key", "keybase:", true) 32 | 33 | violatingEC2Instances = state.filter_attribute_does_not_have_prefix( 34 | allEC2Instances, "instance_type", "m5.", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_does_not_have_suffix.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_does_not_have_suffix 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that does have a specified suffix. A policy would call it when it wants the attribute to end with that suffix. 3 | 4 | It uses Sentinel's standard [strings](https://docs.hashicorp.com/sentinel/imports/strings/) import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_does_not_have_suffix = func(resources, attr, suffix, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should end with the given suffix. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **suffix**: the suffix that the attribute should end with. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) does not end with `suffix`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 29 | ``` 30 | violatingS3Buckets = state.filter_attribute_does_not_have_suffix(allS3Buckets, 31 | "acl", "-full-control", true) 32 | 33 | violatingGCESubnets = state.filter_attribute_does_not_have_suffix( 34 | allGCESubnets, "ip_cidr_range", "/24", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_does_not_match_regex.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_does_not_match_regex 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that does not match a given regular expression (regex). A policy would call it when it wants the attribute to match that regex. 3 | 4 | It uses the Sentinel [matches](https://docs.hashicorp.com/sentinel/language/spec/#matches-operator) operator which uses [RE2](https://github.com/google/re2/wiki/Syntax) regex. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_does_not_match_regex = func(resources, attr, expr, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should match the given regex. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **expr**: the regex expression that should be matched. Note that any occurrences of `\` need to be escaped with `\` itself since Sentinel allows certain special characters to be escaped with `\`. For example, if you wanted to match sub-domains of ".acme.com", you would set `expr` to `(.+)\\.acme\\.com$` instead of the more usual `(.+)\.acme\.com$`. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) does not match the given regex, `expr`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 29 | ``` 30 | violatingACMCerts = state.filter_attribute_does_not_match_regex(allACMCerts, 31 | "domain_name", "(.+)\\.hashidemos\\.io$", true) 32 | 33 | violatingAccessKeys = state.filter_attribute_does_not_match_regex(allAccessKeys, 34 | "pgp_key", "^keybase:(.+)", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_greater_than_value.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_greater_than_value 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that is greater than a given numeric value. A policy would call it when it wants the attribute to be less than or equal to the given value. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_greater_than_value = func(resources, attr, value, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should be less than or equal to a given value. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **value**: the value the attribute should be less than or equal to. This should be an integer or a float. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is greater than the given value, `value`, while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 27 | ``` 28 | highCPUVMs = state.filter_attribute_greater_than_value(allVMs, 29 | "num_cpus", maxCPUs, true) 30 | 31 | 32 | highMemoryVMs = state.filter_attribute_greater_than_value(allVMs, 33 | "memory", maxMemory, true) 34 | 35 | violatingDisks = state.filter_attribute_greater_than_value(disks, 36 | "size", maxDiskSize, false) 37 | ``` 38 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_has_prefix.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_has_prefix 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that has a specified prefix. A policy would call it when it wants the attribute to not start with that prefix. 3 | 4 | It uses Sentinel's standard [strings](https://docs.hashicorp.com/sentinel/imports/strings/) import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_has_prefix = func(resources, attr, prefix, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should not start with the given prefix. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **prefix**: the prefix that the attribute should not start with. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) starts with `prefix`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 29 | ``` 30 | violatingAccessKeys = state.filter_attribute_has_prefix(allAccessKeys, 31 | "pgp_key", "keybase:", true) 32 | 33 | violatingAzureVMs = state.filter_attribute_has_prefix( 34 | allAzureVMs, "vm_size", "Standard_", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_has_suffix.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_has_suffix 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that has a specified suffix. A policy would call it when it wants the attribute to not end with that suffix. 3 | 4 | It uses Sentinel's standard [strings](https://docs.hashicorp.com/sentinel/imports/strings/) import. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_has_suffix = func(resources, attr, suffix, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should not end with the given suffix. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **suffix**: the suffix that the attribute should not end with. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) ends with `suffix`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 29 | ``` 30 | violatingS3Buckets = state.filter_attribute_has_suffix(allS3Buckets, 31 | "acl", "-full-control", true) 32 | 33 | violatingGCESubnets = state.filter_attribute_has_suffix( 34 | allGCESubnets, "ip_cidr_range", "/8", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_in_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_in_list 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute contained in a provided list. A policy would call it when it does not want the attribute set to any member of the list. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_in_list = func(resources, attr, forbidden, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that must not be in a given list. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **forbidden**: a list of values the attribute is forbidden to have. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is in in the list (`forbidden`) while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 27 | ``` 28 | violatingEC2Instances = state.filter_attribute_in_list(allEC2Instances, 29 | "instance_type", forbidden_types, true) 30 | 31 | violatingAzureVMs = state.filter_attribute_in_list(allAzureVMs, 32 | "vm_size", forbidden_sizes, true) 33 | 34 | violatingGCEInstances = state.filter_attribute_in_list(allGCEInstances, 35 | "machine_type", forbidden_types, true) 36 | ``` 37 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_is_not_value.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_is_not_value 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that is not equal to a given value. A policy would call it when it wants the attribute to equal the given value. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_is_not_value = func(resources, attr, value, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should equal a given value. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **value**: the value the attribute should have. This can be any primitive data type. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is not equal to the given value, `value`, while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 27 | ``` 28 | nonPrivateS3Buckets = state.filter_attribute_is_not_value(allS3Buckets, 29 | "acl", "private", true) 30 | 31 | nonEncryptedS3Buckets = state.filter_attribute_is_not_value(allS3Buckets, 32 | "server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm", 33 | "aws:kms", true) 34 | 35 | violatingAzureAppServices = state.filter_attribute_is_not_value(allAzureAppServices, 36 | "https_only", true, true) 37 | ``` 38 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_is_value.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_is_value 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that is equal to a given value. A policy would call it when it wants the attribute to not equal the given value. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_is_value = func(resources, attr, value, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should not equal a given value. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **value**: the value the attribute should not have. This can be any primitive data type. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is equal to the given value, `value`, while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 27 | ``` 28 | nonPrivateS3Buckets = state.filter_attribute_is_value(allS3Buckets, 29 | "acl", "public_read", true) 30 | 31 | 32 | violatingAzureAppServices = state.filter_attribute_is_value(allAzureAppServices, 33 | "https_only", false, true) 34 | ``` 35 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_less_than_value.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_less_than_value 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that is less than a given numeric value. A policy would call it when it wants the attribute to be greater than or equal to the given value. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_less_than_value = func(resources, attr, value, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that should be greater than or equal to a given value. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **value**: the value the attribute should be greater than or equal to. This should be an integer or a float. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is less than the given value, `value`, while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 27 | ``` 28 | lowCPUVMs = state.filter_attribute_less_than_value(allVMs, 29 | "num_cpus", minCPUs, true) 30 | 31 | 32 | lowMemoryVMs = state.filter_attribute_less_than_value(allVMs, 33 | "memory", minMemory, true) 34 | ``` 35 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_matches_regex.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_matches_regex 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that matches a given regular expression (regex). A policy would call it when it wants the attribute to not match that regex. 3 | 4 | It uses the Sentinel [matches](https://docs.hashicorp.com/sentinel/language/spec/#matches-operator) operator which uses [RE2](https://github.com/google/re2/wiki/Syntax) regex. 5 | 6 | ## Sentinel Module 7 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 8 | 9 | ## Declaration 10 | `filter_attribute_matches_regex = func(resources, attr, expr, prtmsg)` 11 | 12 | ## Arguments 13 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 14 | * **attr**: the name of a resource attribute given as a string that should match the given regex. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 15 | * **expr**: the regex expression that should be matched. Note that any occurrences of `\` need to be escaped with `\` itself since Sentinel allows certain special characters to be escaped with `\`. For example, if you did not want to match sub-domains of ".acme.com", you would set `expr` to `(.+)\\.acme\\.com$` instead of the more usual `(.+)\.acme\.com$`. 16 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 17 | 18 | ## Common Functions Used 19 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 20 | 21 | ## What It Returns 22 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) matches the given regex, `expr`, while the `messages` map contains the violation messages associated with those instances. 23 | 24 | ## What It Prints 25 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 26 | 27 | ## Examples 28 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 29 | ``` 30 | violatingACMCerts = state.filter_attribute_matches_regex(allACMCerts, 31 | "domain_name", "(.+)\\.hashidemos\\.io$", true) 32 | 33 | violatingAccessKeys = state.filter_attribute_matches_regex(allAccessKeys, 34 | "pgp_key", "^keybase:(.+)", true) 35 | ``` 36 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_not_contains_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_not_contains_list 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that does not contain all members of a given list. A policy would call it when it wants the attribute to contain all members of the list. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_not_contains_list = func(resources, attr, required, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that must contain all items from a given list. The attribute should be a list or map. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params` rather than `boot_disk[0].initialize_params`. 13 | * **required**: a list of values all of which the attribute should contain. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) does not contain all items of the list (`required`) while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 27 | ``` 28 | violatingEC2Instances = state.filter_attribute_not_contains_list(allEC2Instances, 29 | "tags", mandatory_tags, true) 30 | 31 | violatingAzureVMs = state.filter_attribute_not_contains_list(allAzureVMs, 32 | "tags", mandatory_tags, true) 33 | 34 | violatingGCEInstances = state.filter_attribute_not_contains_list(allGCEInstances, 35 | "labels", mandatory_labels, true) 36 | ``` 37 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/filter_attribute_not_in_list.md: -------------------------------------------------------------------------------- 1 | # filter_attribute_not_in_list 2 | This function filters a collection of resources, data sources, or blocks to those with an attribute that is not contained in a provided list. A policy would call it when it wants the attribute to have a value from the list. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `filter_attribute_not_in_list = func(resources, attr, allowed, prtmsg)` 9 | 10 | ## Arguments 11 | * **resources**: a map of resources derived from [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) or a list of blocks returned by the `find_blocks` function. 12 | * **attr**: the name of a resource attribute given as a string that must be in a given list. If the attribute is nested, the various blocks containing it should be delimited with periods (`.`). Indices of lists should not include brackets and should start with 0. So, you would use `boot_disk.0.initialize_params.0.image` rather than `boot_disk[0].initialize_params[0].image`. 13 | * **allowed**: a list of values the attribute is allowed to have. 14 | * **prtmsg**: a boolean indicating whether violation messages should be printed (if `true`) or not (if `false`). 15 | 16 | ## Common Functions Used 17 | This function calls the [evaluate_attribute](./evaluate_attribute.md) and the [to_string](./to_string.md) functions. 18 | 19 | ## What It Returns 20 | This function returns a map with two maps, `resources` and `messages`, both of which are indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the resources, data sources, or blocks that meet the condition of the filter function. The `resources` map contains the actual resource instances for which the attribute (`attr`) is not in the list (`allowed`) while the `messages` map contains the violation messages associated with those instances. 21 | 22 | ## What It Prints 23 | This function prints the violation messages if the parameter, `prtmsg`, was set to `true`. Otherwise, it does not print anything. 24 | 25 | ## Examples 26 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 27 | ``` 28 | violatingEC2Instances = state.filter_attribute_not_in_list(allEC2Instances, 29 | "instance_type", allowed_types, true) 30 | 31 | violatingAzureVMs = state.filter_attribute_not_in_list(allAzureVMs, 32 | "vm_size", allowed_sizes, true) 33 | 34 | violatingGCEInstances = state.filter_attribute_not_in_list(allGCEInstances, 35 | "machine_type", allowed_types, true) 36 | ``` 37 | 38 | This function is used by the [restrict-current-ec2-instance-type.sentinel (AWS)](../../../aws/restrict-current-ec2-instance-type.sentinel) and [restrict-publishers-of-current-vms.sentinel (Azure)](https://github.com/rberlind/terraform-guides/blob/master/governance/third-generation/azure/restrict-publishers-of-current-vms.sentinel) policies. 39 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/find_blocks.md: -------------------------------------------------------------------------------- 1 | # find_blocks 2 | This function finds all blocks of a specific type under a single resource or block in the state of the current workspace using the [tfstate/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_blocks = func(parent, child)` 9 | 10 | ## Arguments 11 | * **parent**: a single resource or block of a resource 12 | * **child**: a string representing the child blocks to be found in the parent. 13 | 14 | ## Common Functions Used 15 | None 16 | 17 | ## What It Returns 18 | This function returns a single list of child blocks found in the parent resource or block. Each child block is represented by a map. 19 | 20 | ## What It Prints 21 | This function does not print anything. 22 | 23 | ## Examples 24 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 25 | ``` 26 | ingressRules = state.find_blocks(sg, "ingress") 27 | 28 | disks = state.find_blocks(vm, "disk") 29 | ``` 30 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/find_datasources.md: -------------------------------------------------------------------------------- 1 | # find_datasources 2 | This function finds all data source instances of a specific type in the state of the current workspace using the [tfstate/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_datasources = func(type)` 9 | 10 | ## Arguments 11 | * **type**: the type of datasource to find, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of data source instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 24 | ``` 25 | currentAMIs = state.find_datasources("aws_ami") 26 | 27 | currentImages = state.find_datasources("azurerm_image") 28 | 29 | currentImages = state.find_datasources("google_compute_image") 30 | 31 | currentDatastores = state.find_datasources("vsphere_datastore") 32 | ``` 33 | 34 | This function is used by the [restrict-ami-owners.sentinel (AWS)](../../../aws/restrict-ami-owners.sentinel) policy. 35 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/find_datasources_by_provider.md: -------------------------------------------------------------------------------- 1 | # find_datasources_by_provider 2 | This function finds all data source instances for a specific provider in the state of the current workspace using the [tfstate/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_datasources_by_provider = func(provider)` 9 | 10 | ## Arguments 11 | * **provider**: the provider, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of data source instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 24 | ``` 25 | currentAWSDataSources = state.find_datasources_by_provider("aws") 26 | 27 | currentAzureDataSources = state.find_datasources_by_provider("azurerm") 28 | 29 | currentGCPDataSources = state.find_datasources_by_provider("google") 30 | 31 | currentVMwareDataSources = state.find_datasources_by_provider("vsphere") 32 | ``` 33 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/find_resources.md: -------------------------------------------------------------------------------- 1 | # find_resources 2 | This function finds all resource instances of a specific type in the state of the current workspace using the [tfstate/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_resources = func(type)` 9 | 10 | ## Arguments 11 | * **type**: the type of resource to find, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of resource instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 24 | ``` 25 | currentEC2Instances = state.find_resources("aws_instance") 26 | 27 | currentAzureVMs = state.find_resources("azurerm_virtual_machine") 28 | 29 | currentGCEInstances = state.find_resources("google_compute_instance") 30 | 31 | currentVMs = state.find_resources("vsphere_virtual_machine") 32 | ``` 33 | 34 | This function is used by several policies including [restrict-current-ec2-instance-type.sentinel (AWS)](../../../aws/restrict-current-ec2-instance-type.sentinel) and [restrict-publishers-of-current-vms.sentinel (Azure)](../../../azure/restrict-publishers-of-current-vms..sentinel). 35 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/find_resources_by_provider.md: -------------------------------------------------------------------------------- 1 | # find_resources_by_provider 2 | This function finds all resource instances for a specific provider in the state of the current workspace using the [tfstate/v2](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html) import. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `find_resources_by_provider = func(provider)` 9 | 10 | ## Arguments 11 | * **provider**: the provider, given as a string. 12 | 13 | ## Common Functions Used 14 | None 15 | 16 | ## What It Returns 17 | This function returns a single flat map of resource instances indexed by the complete [addresses](https://www.terraform.io/docs/internals/resource-addressing.html) of the instances. The map is actually a filtered sub-collection of the [`tfstate.resources`](https://www.terraform.io/docs/cloud/sentinel/import/tfstate-v2.html#the-resources-collection) collection. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 24 | ``` 25 | currentEC2Resources = state.find_resources_by_provider("aws") 26 | 27 | currentAzureResources = state.find_resources_by_provider("azurerm") 28 | 29 | currentGCPResources = state.find_resources_by_provider("google") 30 | 31 | currentVMwareResources = state.find_resources_by_provider("vsphere") 32 | ``` 33 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/print_violations.md: -------------------------------------------------------------------------------- 1 | # print_violations 2 | This function prints the violation messages that were previously returned by one of the filter functions of the tfstate-functions.sentinel module. While those filter functions can print the violations messages themselves (if their `prtmsg` parameter is set to `true`), it is sometimes preferable to delay printing of the messages until later in the policy, typically after printing one or more messages giving the address of the resource that violated it. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `print_violations = func(messages, prefix)` 9 | 10 | ## Arguments 11 | * **messages**: a map of messages returned by one of the filter functions. 12 | * **prefix**: a string that should be printed before each message. 13 | 14 | ## Common Functions Used 15 | None 16 | 17 | ## What It Returns 18 | This function always returns `true`. 19 | 20 | ## What It Prints 21 | This function prints the messages in the `messages` map prefixed with the `prefix` string. 22 | 23 | ## Examples 24 | Here are some examples of calling this function, assuming that the tfstate-functions.sentinel file that contains it has been imported with the alias `state`: 25 | ``` 26 | if length(violatingIRs["messages"]) > 0 { 27 | violatingSGsCount += 1 28 | print("SG Ingress Violation:", address, "has at least one ingress rule", 29 | "with forbidden cidr blocks") 30 | state.print_violations(violatingIRs["messages"], "Ingress Rule") 31 | } 32 | 33 | if length(violatingDisks["messages"]) > 0 { 34 | disksValidated = false 35 | print(address, "has at least one disk with size greater than", maxDiskSize) 36 | state.print_violations(violatingDisks["messages"], "Disk") 37 | } 38 | ``` 39 | -------------------------------------------------------------------------------- /common-functions/tfstate-functions/docs/to_string.md: -------------------------------------------------------------------------------- 1 | # to_string 2 | This function converts any Sentinel object including complex compositions of primitive types (string, int, float, and bool), null, undefined, lists, and maps to a string. 3 | 4 | ## Sentinel Module 5 | This function is contained in the [tfstate-functions.sentinel](../tfstate-functions.sentinel) module. 6 | 7 | ## Declaration 8 | `to_string = func(obj)` 9 | 10 | ## Arguments 11 | * **obj**: a Sentinel object of any type 12 | 13 | ## Common Functions Used 14 | This function calls itself recursively to support composite objects. 15 | 16 | ## What It Returns 17 | This function returns a single string. 18 | 19 | ## What It Prints 20 | This function does not print anything. 21 | 22 | ## Examples 23 | This function is called by all of the filter functions in the tfstate-functions.sentinel module. Here is a typical example: 24 | ``` 25 | message = to_string(address) + " has " + to_string(attr) + " with value " + 26 | to_string(v) + " that is not in the allowed list: " + 27 | to_string(allowed) 28 | ``` 29 | -------------------------------------------------------------------------------- /gcp/enforce-mandatory-labels.sentinel: -------------------------------------------------------------------------------- 1 | # This policy uses the Sentinel tfplan/v2 import to require that 2 | # all GCE compute instances have all mandatory labels 3 | 4 | # Note that the comparison is case-sensitive but also that GCE labels are only 5 | # allowed to contain lowercase letters, numbers, hypens, and underscores. 6 | 7 | # Import common-functions/tfplan-functions/tfplan-functions.sentinel 8 | # with alias "plan" 9 | import "tfplan-functions" as plan 10 | 11 | # List of mandatory labels 12 | mandatory_labels = ["name", "ttl", "owner"] 13 | 14 | # Get all GCE compute instances 15 | allGCEInstances = plan.find_resources("google_compute_instance") 16 | 17 | # Filter to GCE compute instances with violations 18 | # Warnings will be printed for all violations since the last parameter is true 19 | violatingGCEInstances = plan.filter_attribute_not_contains_list(allGCEInstances, 20 | "labels", mandatory_labels, true) 21 | 22 | # Main rule 23 | main = rule { 24 | length(violatingGCEInstances["messages"]) is 0 25 | } 26 | -------------------------------------------------------------------------------- /gcp/restrict-gce-machine-type.sentinel: -------------------------------------------------------------------------------- 1 | # This policy uses the Sentinel tfplan/v2 import to require that 2 | # all GCE instances have machine types from an allowed list 3 | 4 | # Import common-functions/tfplan-functions/tfplan-functions.sentinel 5 | # with alias "plan" 6 | import "tfplan-functions" as plan 7 | 8 | # Allowed GCE Instance Types 9 | # Include "null" to allow missing or computed values 10 | allowed_types = ["n1-standard-1", "n1-standard-2", "n1-standard-4"] 11 | 12 | # Get all GCE instances 13 | allGCEInstances = plan.find_resources("google_compute_instance") 14 | 15 | # Filter to GCE instances with violations 16 | # Warnings will be printed for all violations since the last parameter is true 17 | violatingGCEInstances = plan.filter_attribute_not_in_list(allGCEInstances, 18 | "machine_type", allowed_types, true) 19 | 20 | # Count violations 21 | violations = length(violatingGCEInstances["messages"]) 22 | 23 | # Main rule 24 | main = rule { 25 | violations is 0 26 | } 27 | -------------------------------------------------------------------------------- /gcp/sentinel.hcl: -------------------------------------------------------------------------------- 1 | module "tfplan-functions" { 2 | source = "../common-functions/tfplan-functions/tfplan-functions.sentinel" 3 | } 4 | 5 | module "tfstate-functions" { 6 | source = "../common-functions/tfstate-functions/tfstate-functions.sentinel" 7 | } 8 | 9 | module "tfconfig-functions" { 10 | source = "../common-functions/tfconfig-functions/tfconfig-functions.sentinel" 11 | } 12 | 13 | policy "enforce-mandatory-labels" { 14 | source = "./enforce-mandatory-labels.sentinel" 15 | enforcement_level = "advisory" 16 | } 17 | 18 | policy "restrict-gce-machine-type" { 19 | source = "./restrict-gce-machine-type.sentinel" 20 | enforcement_level = "advisory" 21 | } 22 | -------------------------------------------------------------------------------- /gcp/test/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rberlind/sentinel-policy-sets-for-tfc/7b69009dc0216c98fe9134b06bd9bfdb2aa44ac7/gcp/test/.DS_Store -------------------------------------------------------------------------------- /gcp/test/enforce-mandatory-labels/fail.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-fail.sentinel" 9 | }, 10 | "test": { 11 | "main": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /gcp/test/enforce-mandatory-labels/pass.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-pass.sentinel" 9 | }, 10 | "test": { 11 | "main": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /gcp/test/restrict-gce-machine-type/fail.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-fail.sentinel" 9 | }, 10 | "test": { 11 | "main": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /gcp/test/restrict-gce-machine-type/pass.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-pass.sentinel" 9 | }, 10 | "test": { 11 | "main": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vmware/restrict-vm-cpu-and-memory.sentinel: -------------------------------------------------------------------------------- 1 | # This policy uses the Sentinel tfplan/v2 import to require that 2 | # all VMware VMs respect CPU and memory limits 3 | 4 | # Import common-functions/tfplan-functions/tfplan-functions.sentinel 5 | # with alias "plan" 6 | import "tfplan-functions" as plan 7 | 8 | # CPU and Memory (MB) Limits 9 | maxCPUs = 4 10 | maxMemory = 8192 11 | 12 | # Get all VMs 13 | allVMs = plan.find_resources("vsphere_virtual_machine") 14 | 15 | # Filter to VMs with high CPU 16 | # Warnings will be printed for all violations since the last parameter is true 17 | highCPUVMs = plan.filter_attribute_greater_than_value(allVMs, 18 | "num_cpus", maxCPUs, true) 19 | 20 | # Filter to VMs with high memory 21 | # Warnings will be printed for all violations since the last parameter is true 22 | highMemoryVMs = plan.filter_attribute_greater_than_value(allVMs, 23 | "memory", maxMemory, true) 24 | 25 | # Main rule 26 | validated = length(highCPUVMs["messages"]) is 0 and length(highMemoryVMs["messages"]) is 0 27 | main = rule { 28 | validated 29 | } 30 | -------------------------------------------------------------------------------- /vmware/restrict-vm-disk-size.sentinel: -------------------------------------------------------------------------------- 1 | # This policy uses the Sentinel tfplan/v2 import to require that 2 | # all VMware VMs obey a disk limit 3 | 4 | # Import common-functions/tfplan-functions/tfplan-functions.sentinel 5 | # with alias "plan" 6 | import "tfplan-functions" as plan 7 | 8 | # Disk Size Limit (in GB) 9 | maxDiskSize = 100 10 | 11 | # Get all VMs 12 | allVMs = plan.find_resources("vsphere_virtual_machine") 13 | 14 | # Validate VM Disks 15 | disksValidated = true 16 | for allVMs as address, vm { 17 | 18 | # Find the disks of the current VM 19 | disks = plan.find_blocks(vm, "disk") 20 | 21 | # Filter to violating disks of the current VM 22 | # Warnings will not be printed for violations since the last parameter is false 23 | violatingDisks = plan.filter_attribute_greater_than_value(disks, 24 | "size", maxDiskSize, false) 25 | 26 | # Print warnings if any violating disks 27 | if length(violatingDisks["messages"]) > 0 { 28 | disksValidated = false 29 | print(address, "has at least one disk with size greater than", maxDiskSize) 30 | plan.print_violations(violatingDisks["messages"], "Disk") 31 | } // end if 32 | 33 | } // end for VMs 34 | 35 | # Main rule 36 | main = rule { 37 | disksValidated 38 | } 39 | -------------------------------------------------------------------------------- /vmware/sentinel.hcl: -------------------------------------------------------------------------------- 1 | module "tfplan-functions" { 2 | source = "../common-functions/tfplan-functions/tfplan-functions.sentinel" 3 | } 4 | 5 | module "tfstate-functions" { 6 | source = "../common-functions/tfstate-functions/tfstate-functions.sentinel" 7 | } 8 | 9 | module "tfconfig-functions" { 10 | source = "../common-functions/tfconfig-functions/tfconfig-functions.sentinel" 11 | } 12 | 13 | policy "restrict-vm-cpu-and-memory" { 14 | source = "./restrict-vm-cpu-and-memory.sentinel" 15 | enforcement_level = "advisory" 16 | } 17 | 18 | policy "restrict-vm-disk-size" { 19 | source = "./restrict-vm-disk-size.sentinel" 20 | enforcement_level = "advisory" 21 | } 22 | -------------------------------------------------------------------------------- /vmware/test/restrict-vm-cpu-and-memory/fail-cpu-and-memory.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-fail-cpu-and-memory.sentinel" 9 | }, 10 | "test": { 11 | "main": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vmware/test/restrict-vm-cpu-and-memory/fail-cpu.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-fail-cpu.sentinel" 9 | }, 10 | "test": { 11 | "main": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vmware/test/restrict-vm-cpu-and-memory/fail-memory.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-fail-memory.sentinel" 9 | }, 10 | "test": { 11 | "main": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vmware/test/restrict-vm-cpu-and-memory/pass.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-pass.sentinel" 9 | }, 10 | "test": { 11 | "main": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vmware/test/restrict-vm-disk-size/fail.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-fail.sentinel" 9 | }, 10 | "test": { 11 | "main": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vmware/test/restrict-vm-disk-size/pass.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": { 3 | "tfplan-functions": { 4 | "path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel" 5 | } 6 | }, 7 | "mock": { 8 | "tfplan/v2": "mock-tfplan-pass.sentinel" 9 | }, 10 | "test": { 11 | "main": true 12 | } 13 | } 14 | --------------------------------------------------------------------------------