# Azure Nag Static Analysis Tool

![azure-nag](https://github.com/stelligent/azure-nag/workflows/azure-nag/badge.svg)
![releases](https://github.com/stelligent/azure-nag/workflows/releases/badge.svg)
![vscode-container](https://github.com/stelligent/azure-nag/workflows/vscode-container/badge.svg)
![azure-nag-docker-image](https://github.com/stelligent/azure-nag/workflows/azure-nag-docker-image/badge.svg)

# Background
azure-nag checks Azure Resource Manager (ARM) templates for patterns that may defy best practices or indicate insecure resources.  It is built using [Stelligent mc-nag](https://github.com/stelligent/mc-nag) as the base engine.

# Prerequisites

* Python >=3.7
* mc-nag

# Installation

`pip install azure-nag`

# Usage

`azure-nag` is the main entry point for the utility.  It handles parsing, modeling, rule execution against, and reporting on templates passed to it.  When used with the `--rules` flag, it will also display information about all available rules.

```
$ azure-nag --help
Usage: azure-nag [OPTIONS]

  Perform template parsing and rule evaluation.

Options:
  --enable-standard-rules / --disable-standard-rules
                                  Enable/disable the standard rule set that
                                  ships with mc-nag.

  -C, --custom-platform-rules-dir PATH
                                  Path to a directory containing custom rules.
                                  Allows multiple.

  -lt, --list-tags                List of all available tags.
  -t, --enable-tags-only TEXT     A quoted list of tags. Scan only those
                                  Rules.

  --rules                         Display information about all available
                                  rules.

  -f, --filepath PATH
  -o, --output [text|json|yaml|none]
  -p, --paramfile PATH
  --rule-param TEXT               Pass parameters through to rules.  Allows
                                  multiple. Format: --rule-param param1=value1
                                  --rule-param param2=value2

  -v, --verbose
  --help                          Show this message and exit.
```

# Development

## VS Code Remote Development
There is a complete remote development environment created and setup with all the tools and settings pre-configured for ease in rule development and creation. You can enable this by using the VS Code Remote development functionality.

- Install the VS Code [Remote Development extension pack](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack)
- Open the repo in VS Code
- When prompted "`Folder contains a dev container configuration file. Reopen folder to develop in a container`" click the "`Reopen in Container`" button
- When opening in the future use the "`[Dev Container] azure_nag Development`" option

If you would like to mount a local copy of the `mc_nag` package inside this development container for easier dev iterations, you can set the `MCNAG_PATH` environment variable before launching VSCode.  It should point to the `mc_nag` package directory within the `mc-nag` repository directory.
For example:
```
export MCNAG_PATH=/home/user/mc-nag-repo-clone/mc_nag
```

The `mc_nag` directory will be mounted in your container's workspace at the root level of the `azure-nag` repository files.

## Rule Creation

Rules are at the crux of azure-nag's purpose.  They create its functionality but are flexible enough to be able to create/update/delete them at will.  azure-nag comes with a [default set of rules](azure_nag/rules) created by the Stelligent azure-nag team, however it also offers a [`--custom-platform-rules-dir` CLI option](#Usage).

If you believe a rule should be added to the standard rule set packaged with azure-nag, feel free to create the new rule and submit it as a [pull request in the stelligent/azure-nag repository](https://github.com/stelligent/azure-nag/pulls).

### Structure

All rules must be subclassed from the [`BaseRule` class](https://github.com/stelligent/mc-nag/mc_nag/base_utils/models/rule.py).  It contains the basic necessities and structure for a rule class, as well as validation mechanisms to ensure your rule class will behave as expected.

Rules accept parameters from the CLI when passed in using the `--rule-param` option (see [Usage](#Usage) above).  Parameters are passed into the `BaseRule __init__()` method and made available as class attributes for use in any class method including `evaluate()`.  You can also set default values for attributes in your rule class and override them with the `--rule-param` option (see [an example here](https://github.com/stelligent/mc-nag/blob/feature/rule-args/tests/rules/with_params/some_threshold_rule.py)).

Every rule must have at least:
* **Attributes**
  * *rule_id*: Unique identifier for the rule.
  * *description*: Plain language description of what the rule is trying to accomplish.
  * *severity*: The impact the rule has on the run of azure-nag.  One of [`rule.ERROR`, `rule.WARNING`, `rule.STYLE`].
  * *url*: Page at which more information can be found on the rule.
  * *resolution*: Steps to take in order to remediate any violations the rule finds.
* **Methods**
  * *evaluate*: Logic to perform the rule's stated function.  Must return a list of violating resources.

[Sample rule](azure_nag/rules/azure_storageaccount_encrypted_rule.py) which shows basic structure

### Testing

It is good practice to create unit tests and multiple example templates to accompany your new rule in order to prove your rule logic works properly.  Tests should consider both good and bad scenarios, as well as any novel scenarios which may crop up in practice.

When you have a rule ready for evaluation, you can either pass its containing directory as a `--custom-platform-rules-dir` CLI option to the azure-nag executable or, if you have the azure-nag source checked out, you can place the rule into [azure_nag/rules](azure_nag/rules).

[Sample unit tests](tests/rules/test_azure_storageaccount_encrypted_rule.py)

[Sample test templates](tests/templates/azure_storageAccounts)

## Template Model Creation

The template model is a generic way to represent different platforms' templates.  After a template is parsed, its parsed data is stored in the template model for evaluation by the rule set.

### Structure

All template models must be subclassed from the [`BaseTemplate` class](https://github.com/stelligent/mc-nag/mc_nag/base_utils/models/template.py).  It contains the basic necessities and structure for a template model class, as well as validation mechanisms to ensure your template model class will behave as expected.

Every template model must have at least:
* **Attributes**
  * *template_string*: Raw string read from the template file.
  * *parsed_template*: Parser object (e.g. [`AzureParser`](azure_nag/azure_parser.py)), which returns the parsed template model.
  * *resources*: List of resource objects (e.g. [`AzureResource`](azure_nag/models/azure_resource.py)) created from the parsed template model.
  * *parameters*: List of parameter objects (e.g. [`AzureParameter`](azure_nag/models/azure_parameter.py)) created from the parsed template model.
  * *outputs*: List of output objects (e.g. [`AzureOutput`](azure_nag/models/azure_output.py)) created from the parsed template model.
  * *functions*: List of function objects (e.g. [`AzureFunction`](azure_nag/models/azure_function.py)) created from the parsed template model.
  * *variables*: List of variable objects (e.g. [`AzureVariable`](azure_nag/models/azure_variable.py)) created from the parsed template model.

The attributes listed above must be defined, even if they are just empty lists.

[Sample template model](azure_nag/models/azure_template.py) which shows basic structure

### Testing

It is also a good practice to create unit tests and multiple example templates to accompany your new template model in order to prove your data model logic works properly.  Tests should consider both good and bad scenarios, as well as any novel scenarios which may crop up in practice.

[Sample unit tests](tests/test_azure_template.py)

[Sample test templates](tests/templates)

# Running with Docker
The azure-nag tool is also available to be ran as a container with the azure-nag Docker image.
https://hub.docker.com/r/stelligent/azure-nag
1. Pull the latest azure-nag Docker image: `docker pull stelligent/azure-nag:latest`
2. Running the container against an Azure template:
    - `docker run -v $(pwd)/<ARM_TEMPLATE_DIR>:/templates stelligent/azure-nag:latest --filepath /templates/<ARM_TEMPLATE>.json`
3. Running the container against an Azure template with passing in a parameters JSON file:
    - `docker run -v $(pwd)/<ARM_TEMPLATE_DIR>:/templates stelligent/azure-nag:latest --filepath /templates/<ARM_TEMPLATE>.json --paramfile /templates/<PARAMETERS_FILE>.json`

# Support

To report a bug or request a feature, submit an issue through the stelligent/mc-nag GitHub repository via https://github.com/stelligent/azure-nag/issues/new.
