# Policies

## Overview

Policies are used to identify misconfigured cloud infrastructure and generate alerts for your team. Panther provides a number of already written and continuously updated [Panther-managed policies](https://docs.panther.com/detections/panther-managed).

Policies may be written as [Python detections](https://docs.panther.com/detections/rules/python); they cannot be written as [Simple Detections](https://docs.panther.com/detections/rules/writing-simple-detections).

Matches on policies create compliance failures, but not [signals](https://docs.panther.com/detections/signals). Compliance failures are visible:

* In [Data Explorer](https://docs.panther.com/search/data-explorer), in the `panther_cloudsecurity.public` database, in the `compliance_history` table
* In [Search](https://docs.panther.com/search/search-tool), in the **Could Security** database, in the **Compliance History** table

## How to write a policy

Before you start writing a new policy, remember to check to see if there's an existing [Panther-managed policy](https://docs.panther.com/detections/panther-managed) that meets your needs.

{% hint style="warning" %}
It is highly discouraged to make external API requests from within your detections in Panther. In general, detections are processed at a very high scale, and making API requests can overload receiving systems and cause your rules to exceed the [15-second runtime limit](https://docs.panther.com/rules#rule-errors-and-scheduled-rule-errors).
{% endhint %}

### Policy body

The policy body must:

* Be valid Python3.
* Define a `policy()` function that accepts one `resource` argument.
  * Each policy takes a `resource` input of a given resource type from the [supported resources](https://docs.panther.com/cloud-scanning/cloud-resource-attributes) page.
* Return a `bool` from the policy function.

```python
def policy(resource):
  return True
```

The Python body should name the argument to the `policy()` function `resource` and also may do the following:

* Import standard Python3 libraries
* Import from the user defined `aws_globals` module
* Import from the Panther defined `panther` module
* Define additional helper functions as needed
* Define variables and classes outside the scope of the rule function

Using the schemas in [supported resources](https://docs.panther.com/cloud-scanning/cloud-resource-attributes) provides details on all available fields in resources. Top level keys are always present, although they may contain `NoneType` values.

### Writing policies locally and in the Panther Console

You can write and deploy policies in the Panther Console or you can write them locally and upload them to Panther using the [Panther Analysis Tool (PAT)](https://docs.panther.com/panther-developer-workflows/detections-repo/pat) CLI workflow:

{% tabs %}
{% tab title="Console" %}
**How to write policies in the Panther Console**

1. In the left-hand navigation bar of your Panther Console, click **Detections**.
2. In the upper-right corner, click **Create New**.
3. In the **Policy** tile, click **Start**.
4. On the create page, configure your policy:
   * **Name**: Enter a descriptive name for the policy.
   * **ID** (optional)**:** Click the pen icon and enter a unique ID for your policy.
   * In the upper-right corner, the **Enabled** toggle will be set to `ON` by default. If you'd like to disable the policy, flip the toggle to `OFF`.
   * In the **For the Following Resource Types** section:
     * **Resource Types**: Select one or more resource types this policy should apply to. Leave empty to apply to all resources.
   * In the **Detect** section:
     * In the **Policy Function** text editor, write a Python `policy` function to define your detection.
       * For detection templates and examples, see the [panther\_analysis GitHub repository](https://github.com/panther-labs/panther-analysis/tree/master/templates)
   * In the **Set Alert Fields** section:
     * **Severity**: Select a [severity level](https://docs.panther.com/rules#alert-severity) for the alerts triggered by this detection.
     * In the **Optional Fields** section, optionally provide values for the following fields:
       * **Description**: Enter additional context about the policy.
       * **Runbook**: Enter the procedures and operations relating to this policy.
         * Learn more on [Alert Runbooks](https://docs.panther.com/alerts/alert-runbooks).
         * It's recommended to provide a descriptive runbook, as [Panther AI alert triage](https://docs.panther.com/alerts#panther-ai-alert-triage) will take it into consideration.
       * **Reference**: Enter an external link to more information relating to this rule.
       * **Destination Overrides:** Choose destinations to receive alerts for this detection, regardless of severity. Note that destinations can also be set dynamically, in the rule function. See [Routing Order Precedence](https://docs.panther.com/alerts/destinations#routing-order-precedence) to learn more about routing precedence.
       * **Ignore Patterns**: Enter patterns to ignore.
       * **Custom Tags**: Enter custom tags to help you understand the rule at a glance (e.g., `HIPAA`.)
       * In the **Framework Mapping** section:
         1. Click **Add New** to enter a report.
         2. Provide values for the following fields:
            * **Report Key**: Enter a key relevant to your report.
            * **Report Values**: Enter values for that report.
   * In the **Test** section:
     * In the **Unit Test** section, click **Add New** to [create a test](https://docs.panther.com/detections/testing) for the policy you defined in the previous step.
5. In the upper-right corner, click **Save**.
   {% endtab %}

{% tab title="CLI" %}
We recommend managing your local detection files in a version control system like GitHub or GitLab.

{% hint style="info" %}
It's best practice to create a fork of Panther's [open-source analysis repository](https://github.com/panther-labs/panther-analysis), but you can also create your own repo from scratch.
{% endhint %}

**File setup**

Each detection consists of:

* A Python file (a file with a `.py` extension) containing your detection/audit logic
* A YAML or JSON specification file (a file with a `.yml` or `.json` extension) containing metadata attributes of the detection.
  * By convention, we give this file the same name as the Python file.

**Folder setup**

If you group your policies into folders, each folder name must contain `policies` in order for them to be found during upload (using either PAT or the bulk uploader in the Console).

We recommend grouping policies into folders based on log/resource type, e.g., `suricata_rules` or `aws_s3_policies`. You can use the open source [Panther Analysis](https://github.com/panther-labs/panther-analysis) repo as a reference.

**Writing policies locally**

1. Write your policy and save it (in your folder of choice) as `my_new_policy.py`:\
   def polcy(resource):

   ```
   def policy(resource):  
     return resource['Region'] != 'us-east-1'
   ```
2. Create a specification file using the template below:

   ```
   AnalysisType: policy
   Enabled: true
   Filename: my_new_policy.py
   PolicyID: Category.Type.MoreInfo
   ResourceType:
     - Resource.Type.Here
   Severity: Info|Low|Medium|High|Critical
   DisplayName: Example Policy to Check the Format of the Spec
   Tags:
     - Tags
     - Go
     - Here
   Runbook: Find out who changed the spec format.
   Reference: https://www.link-to-info.io
   ```

See the full [Python policy specification reference on Writing Python Detections](https://docs.panther.com/rules/python#python-policy-specification-reference) for a complete list of required and optional fields.
{% endtab %}
{% endtabs %}

## Title of associated alerts

The order of precedence for setting the alert title for policies is the same as it is for Rules and Scheduled Rules—see the [How the alert title is set](https://docs.panther.com/rules#how-the-alert-title-is-set) section.

## Ignoring specific cloud resources

It's possible to configure a policy to make exceptions for certain cloud resources, meaning the policy will not be run over those resources and alerts will not be generated. This is sometimes referred to as a "policy suppression."

There are three ways to configure a policy suppression:

{% tabs %}
{% tab title="Console: Resource page" %}
{% hint style="warning" %}
If you are configuring a [Panther-managed](https://docs.panther.com/detections/panther-managed) policy suppression, it is not reversible.
{% endhint %}

{% hint style="info" %}
While it's possible to *add* a policy suppression from the resource's page in the Panther Console, if you need to later remove it, you must edit the policy via one of the two other methods.
{% endhint %}

To configure a policy to ignore a resource from the resource's page in the Panther Console:

1. In the left-hand navigation bar of your Panther Console, click **Cloud Resources**.
2. Click the name of the cloud resource you'd like to ignore.
3. In the **Policies** section, which contains all the policies that are applied to this resource, locate the policy you'd like to configure to ignore this resource.
4. On the right side of its row, click the three dots icon, then **Ignore**.
   * This edits the policy, adding to its **Ignore Patterns** field.

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-0ef5b62541fd5ea724ed7707d27f6fe8a9af4f0c%2FScreenshot%202023-12-12%20at%201.20.06%E2%80%AFPM.png?alt=media" alt="A &#x22;Policies&#x22; section shows three policies in a table. Each policy has a status, severity, and a three dots icon."><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Console: Policy page" %}
To configure a policy to ignore a resource from the policy's page in the Panther Console:

1. In the left-hand navigation bar of your Panther Console, click **Build** > **Detections**.
2. Click the name of the policy you'd like to configure a suppression for.
3. In the **Set Alert Fields** section, expand the **Optional Fields** dropdown.
4. In the **Ignore Patterns** field, enter the ARN of the resource(s) you want to ignore.
   * You can ignore multiple resources with similar ARNs using a wildcard pattern. For example, you can exclude all S3 buckets with titles starting with `panther` by entering `arn:aws:s3:::panther*`.

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-e1078da32fad2ae5648a644c2aca7a956861e9b2%2FScreenshot%202023-12-12%20at%201.28.52%E2%80%AFPM.png?alt=media" alt="An &#x22;Ignore Patterns&#x22; field has a value of &#x22;arn:aws:s3:::panther*&#x22;"><figcaption></figcaption></figure>
{% endtab %}

{% tab title="CLI: Policy configuration" %}
To configure a policy to ignore a resource from the policy's local file configuration:

1. Open the YAML file for your policy.
2. Add a new field, called `Suppressions` with type `array`.
   * Learn more about this field in the [Python Policy Specification Reference](https://docs.panther.com/rules/python#python-policy-specification-reference).
3. Under `Suppressions`, add the resource ARN(s) you'd like to ignore as a list.
   * You can ignore multiple resources with similar ARNs using a wildcard pattern. For example, you can exclude all S3 buckets with titles starting with `panther` by entering `arn:aws:s3:::panther*`.

Example:

```yaml
AnalysisType: policy
PolicyID: AWS.S3.CustomPolicy.Example
...
Suppressions:
  - "arn:aws:s3:::test-bucket"
  - "arn:aws:s3:::panther*"
```

{% endtab %}
{% endtabs %}

## Policy Writing Best Practices

### Constructing Test Resources

Manually building test cases can be prone to human error. We suggest one of the following methods:

* Option 1: In the Panther Console, navigate to **Investigate > Cloud Resources**. Apply a filter of the resource type you intend to emulate in your test. Select a resource in your environment, and on the `Attributes` card you can copy the full JSON representation of that resource by selecting copy button next to the word `root`.
* Option 2: Open the Panther [Resources documentation](https://docs.panther.com/cloud-scanning/cloud-resource-attributes), and navigate to the section for the resource you are trying to emulate. Copy the provided example resource. Paste this in to the resource editor if you're working in the web UI, or into the `Resource` field if you are working locally. Now you can manually modify the fields relevant to your policy and the specific test case you are trying to emulate.

Option 1 is best when it is practical, as this can provide real test data for your policies. Additionally, it is often the case that you are writing/modifying a policy specifically because of an offending resource in your account. Using that exact resource's JSON representation as your test case can guarantee that similar resources will be caught by your policy in the future.

### Debugging Exceptions

Debugging exceptions can be difficult, as you do not have direct access to the Python environment running the policies.

When you see a policy that is showing the state `Error` on a given resource, that means that the policy threw an exception. The best method for troubleshooting these errors is to use option 1 in the [**Constructing test resources**](#constructing-test-resources) section above and create a test case from the resource causing the exception.

Running this test case either locally or in the Panther Console should provide more context for the issue, and allow you to modify the policy to debug the exception without having to run the policy against all resources in your environment.

{% hint style="warning" %}
Note: Anything printed to `stdout` or `stderr` by your Python code will end up in CloudWatch. For SaaS/CPaaS customers, Panther engineers can see these CloudWatch logs during routine application monitoring.
{% endhint %}

## Policy examples

### S3 public read access

In the example below, the policy checks if an S3 bucket allows public read access:

```python
# A list of grantees that represent public access
GRANTEES = {
    'http://acs.amazonaws.com/groups/global/AuthenticatedUsers',
    'http://acs.amazonaws.com/groups/global/AllUsers'
}
PERMISSIONS = {'READ'}


def policy(resource):
    for grant in resource['Grants']:
        if grant['Grantee']['URI'] in GRANTEES and grant[
                'Permission'] in PERMISSIONS:
            return False

    return True
```

### IAM Password Policy

This example policy alerts when the password policy does not enforce a maximum password age:

```python
def policy(resource):
    if resource['MaxPasswordAge'] is None:
        return False
    return resource['MaxPasswordAge'] <= 90
```

In the `policy()` body, returning a value of `True` indicates the resource is compliant and no alert should be sent. Returning a value of `False` indicates the resource is non-compliant.

The policy is based on an [IAM Password Policy](https://docs.panther.com/cloud-scanning/cloud-resource-attributes/aws/password-policy) resource:

```javascript
{
    "AccountId": "123456789012",
    "AllowUsersToChangePassword": true,
    "AnyExist": true,
    "ExpirePasswords": true,
    "HardExpiry": null,
    "MaxPasswordAge": 90,
    "MinimumPasswordLength": 14,
    "Name": "AWS.PasswordPolicy",
    "PasswordReusePrevention": 24,
    "Region": "global",
    "RequireLowercaseCharacters": true,
    "RequireNumbers": true,
    "RequireSymbols": true,
    "RequireUppercaseCharacters": true,
    "ResourceId": "123456789012::AWS.PasswordPolicy",
    "ResourceType": "AWS.PasswordPolicy",
    "Tags": null,
    "TimeCreated": null
}
```

## Reference

* See the full [Python policy specification reference on Writing Python Detections](https://docs.panther.com/rules/python#python-policy-specification-reference).
