diff --git a/CHANGELOG.md b/CHANGELOG.md index a34f4474..1967be7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed — verdicts + +Read this section before upgrading: it changes what some policies report, on inputs where the +previous answer was wrong. + +- `core`: a tolerated provider miss no longer erases a failure recorded by an earlier resource. + A check whose provider returned several results — one that violated the policy and one it could + not read, tolerated by `error_tolerance` — reported the *skip* if the tolerated one came last, + because the skip marker overwrote the verdict unconditionally. The verdict therefore depended on + the order the provider happened to emit resources. It now reports the failure regardless of + order. Under `--fail-on-error` the affected runs move from exit `1` to exit `3`: previously a + real violation could be reported as "nothing was checked". Pass-and-skip is unchanged and still + reports skipped, in both orders. + ### Added + +- Running many policies in one invocation. `-policy-path` accepts a **directory**, walked + recursively for `*.json`, and `--pack NAME` runs a policy pack bundled with Tirith + (`--list-packs` lists them). Both are repeatable and combine, so bundled and local rules produce + one summary and one exit code. A single policy *file* is untouched — same result document, same + exit codes. +- The first bundled pack: **`terraform-baseline`**, 104 baseline security and configuration checks + for Terraform plans across AWS, Azure, GCP, Kubernetes and several smaller providers. Every one + is verified end to end in CI against a compliant and a violating document, so an engine change + cannot silently turn a check into a no-op. +- A set run reports `passed / failed / skipped / errored` and prints failures in full. **Skipped is + not a failure**: a policy only applies to plans that touch the resource it names, so most of a + large pack skips on any given plan, and counting that as an error would make every pack run red. + With `--fail-on-error`, a set exits `3` if any policy failed, `0` if none failed and at least one + reached a verdict, and `1` if nothing reached one. - `tirith ui`: an interactive interface with three tabs. - **Explorer** — read an evaluation's results down to the resource behind each one. The result document has always carried the resource address, the planned action and the before/after diff --git a/MANIFEST.in b/MANIFEST.in index 3074ec4d..2e91268d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ include *.lock include *.md +include NOTICE include Pipfile recursive-include ci *.gitkeep recursive-include cli *.sh diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..03328c60 --- /dev/null +++ b/NOTICE @@ -0,0 +1,23 @@ +Tirith +Copyright StackGuardian + +This product includes software developed at StackGuardian (https://stackguardian.io). + +-------------------------------------------------------------------------------- +Bundled policy packs +-------------------------------------------------------------------------------- + +The policy documents under `src/tirith/packs/` are derived works: their rules were +translated into Tirith's policy format from open-source policy libraries, then +re-expressed, re-identified and independently verified against synthesized +documents. They carry StackGuardian identifiers and no upstream identifier. + +The rules they express derive from: + + checkov -- https://github.com/bridgecrewio/checkov + Copyright 2019 Bridgecrew, Inc. + Licensed under the Apache License, Version 2.0 + Pinned at commit 9514f12d81ebec7a8f6e70ff1ae8c3783220a59f + +Tirith is itself licensed under the Apache License, Version 2.0; see LICENSE. +Each pack's `pack.json` records the corpus commit its content was generated from. diff --git a/README.md b/README.md index ffbc2883..783bc905 100644 --- a/README.md +++ b/README.md @@ -186,14 +186,17 @@ Congratulations! Tirith has been setup in your system ## Usage ``` -usage: tirith [-h] [-policy-path PATH] [-input-path PATH] [-var-path PATH] - [-var PATH] [--json] [--verbose] [--fail-on-error] [--version] +usage: tirith [-h] [-policy-path PATH] [--pack NAME] [--list-packs] + [-input-path PATH] [-var-path PATH] [-var PATH] [--json] + [--verbose] [--fail-on-error] [--version] Tirith (StackGuardian Policy Framework) options: -h, --help show this help message and exit - -policy-path PATH Path containing Tirith policy as code + -policy-path PATH Path to a Tirith policy file, or a directory of them + --pack NAME Bundled policy pack(s) to run. Repeatable, and combines with -policy-path. + --list-packs List the policy packs bundled with this installation and exit -input-path PATH Input file path -var-path PATH Variable file path(s) -var PATH Inline variable(s) diff --git a/documentation/docs/tirith-policies/tirith-policy-packs.md b/documentation/docs/tirith-policies/tirith-policy-packs.md new file mode 100644 index 00000000..8926ee26 --- /dev/null +++ b/documentation/docs/tirith-policies/tirith-policy-packs.md @@ -0,0 +1,106 @@ +--- +id: tirith-policy-packs +title: Policy Packs +sidebar_label: Policy Packs +description: Run many Tirith policies in one invocation, and the packs bundled with Tirith. +keywords: + - tirith + - policy pack + - predefined policies +site_name: Tirith +slug: tirith-policy-packs/ +--- + +A **pack** is a named set of policies that ships inside Tirith. Nothing about a packed policy is +special — each one is an ordinary Tirith policy document, run through the same engine as a file +you pass with `-policy-path`. The pack is only a name for a set, so that there is something to +type. + +## Running one + +```bash +tirith --list-packs +tirith --pack terraform-baseline -input-path plan.json --fail-on-error +``` + +`--pack` is repeatable, and combines with `-policy-path`, so your own rules run alongside the +bundled ones in a single invocation and a single verdict: + +```bash +tirith --pack terraform-baseline -policy-path .tirith/policies -input-path plan.json +``` + +## Running a directory + +`-policy-path` also accepts a directory, which is walked recursively for `*.json`: + +```bash +tirith -policy-path .tirith/policies -input-path plan.json +``` + +## Reading the result + +A run of more than one policy reports a summary rather than every policy in full: + +``` +104 policies · 5 passed · 2 failed · 97 skipped +Skipped policies found no resource of the type they check. + +✘ 2 policy/policies failed +``` + +**Most policies skipping is the normal outcome, not a problem.** A check applies only to plans +that touch the resource it names, so a plan that creates one EC2 instance leaves almost every +check in a large pack with nothing to look at. Those policies are counted as `skipped`; they are +neither a pass nor a failure, and they do not affect the exit code. Failures are printed in full, +because they are the reason you ran it. `--verbose` prints every policy. + +`--json` returns the aggregate document: + +```json +{ + "summary": {"total": 104, "passed": 5, "failed": 2, "skipped": 97, "errored": 0}, + "final_result": false, + "policies": [ + {"policy": "terraform-baseline/SG_TF_0042_aws_s3_bucket_versioning.json", "meta": {}, "final_result": false, "evaluators": []} + ] +} +``` + +Each entry in `policies` is exactly the result document a single-policy run produces, plus a +`policy` name, so anything that already reads a Tirith result can read one of these. + +A single policy **file** is unchanged: it returns the single-policy document and the exit codes it +always has. The shape follows how the run was asked for — a directory or a `--pack` is a set — not +how many policies happened to match, so a directory holding one policy still reports as a set. + +## Exit codes + +With `--fail-on-error`: + +| Situation | Code | +|---|---| +| At least one policy failed | `3` | +| No failures, at least one policy reached a verdict | `0` | +| Nothing ran, or every policy skipped | `1` | + +Skipped policies never produce `3`. A pack whose policies all skipped exits `1`, on the same rule +the single-policy path applies to `final_result: null`: nothing was checked, so nothing can be +reported as green. + +## Bundled packs + +| Pack | Policies | Scope | +|---|---|---| +| `terraform-baseline` | 104 | Baseline security and configuration checks for Terraform plans, across AWS, Azure, GCP, Kubernetes and several smaller providers | + +Every policy in a bundled pack has been verified end to end: it passes a compliant document and +fails a violating one, and those fixtures are run in Tirith's own CI, so an engine change cannot +silently turn a check into a no-op. + +### Identifiers and tags + +Packed policies carry a StackGuardian id — `SG_TF_0042` — that is allocated once and never +reassigned, so a report can name a check and mean the same check next release. `meta.tags` carry a +`cloud:` tag plus the policy's category, and are the seam that compliance-framework tags +will slot into. diff --git a/documentation/docs/tirith-usage/cli-reference.md b/documentation/docs/tirith-usage/cli-reference.md index b8a726c5..5bfd8308 100644 --- a/documentation/docs/tirith-usage/cli-reference.md +++ b/documentation/docs/tirith-usage/cli-reference.md @@ -30,7 +30,9 @@ Note the spelling: the path and variable options take a **single dash** (`-polic | Flag | Argument | What it does | |---|---|---| -| `-policy-path` | `PATH` | Path to the Tirith policy file. Required. | +| `-policy-path` | `PATH` | Path to a Tirith policy file, or a directory of them. Required unless `--pack` is given. | +| `--pack` | `NAME` | A bundled policy pack to run. Repeatable, and combines with `-policy-path`. | +| `--list-packs` | | List the packs bundled with this installation and exit. | | `-input-path` | `PATH` | Path to the document the policy is evaluated against. Required. | | `-var-path` | `PATH` | Path to a JSON file of policy variables. Repeatable. | | `-var` | `NAME=JSON` | One inline policy variable. Repeatable. | @@ -48,7 +50,23 @@ See the [policy reference](../tirith-policies/tirith-policy-reference.md) for th [providers overview](../tirith-providers/overview.md) for what kinds of input each `required_provider` reads. -If the flag is missing, `tirith` prints an error to stderr and exits `1`. +Given a **directory**, it is walked recursively and every `*.json` in it is evaluated against the +same input, with the verdicts rolled up into one summary and one exit code — see +[policy packs](../tirith-policies/tirith-policy-packs.md). + +If neither this flag nor `--pack` is given, `tirith` prints an error to stderr and exits `1`. + +### `--pack` + +A set of policies bundled with Tirith, run by name: + +```bash +tirith --list-packs +tirith --pack terraform-baseline -input-path plan.json --fail-on-error +``` + +Repeatable, and combines with `-policy-path`, so your own rules and the bundled ones produce one +verdict. An unknown pack name exits `1`. See [policy packs](../tirith-policies/tirith-policy-packs.md). ### `-input-path` diff --git a/documentation/docs/tirith-usage/exit-codes.md b/documentation/docs/tirith-usage/exit-codes.md index cac5ad99..a62f9e70 100644 --- a/documentation/docs/tirith-usage/exit-codes.md +++ b/documentation/docs/tirith-usage/exit-codes.md @@ -36,6 +36,17 @@ Both surfaces **fail closed**: anything that leaves the verdict unknown exits no of `--fail-on-error`. That flag governs policy verdicts, not tool health — a run that produced no verdict must never look like a pass. +## Running more than one policy + +A directory of policies or a `--pack` produces one exit code for the whole set, on the same rules: +`3` if any policy failed, `0` if none failed and at least one reached a verdict, `1` if nothing +ran or every policy skipped. + +A **skipped** policy — one whose resource type is absent from the input — never produces `3`. For +a pack of any size that is the normal outcome for most policies, since a check only applies to +plans that touch the resource it names; counting skips as failures would make every pack run red +regardless of the infrastructure. + ## Without `--fail-on-error` The local command exits `0` whether the policy passed or failed, with the verdict in the output. diff --git a/documentation/sidebars.js b/documentation/sidebars.js index 69f42e86..2f70cb07 100644 --- a/documentation/sidebars.js +++ b/documentation/sidebars.js @@ -40,6 +40,7 @@ module.exports = { "tirith-policies/tirith-policy-conditions", "tirith-policies/tirith-policy-variables", "tirith-policies/tirith-policy-cookbook", + "tirith-policies/tirith-policy-packs", // "tirith-policies/tirith-policy-examples" ] }, diff --git a/setup.py b/setup.py index 6dc8be09..6b6e9328 100644 --- a/setup.py +++ b/setup.py @@ -45,6 +45,9 @@ def read(*names, **kwargs): package_data={ "tirith.tui": ["*.css"], "tirith.tui.examples": ["*/*.json", "*/*.md"], + # The bundled policy packs. Without these `--pack` finds nothing and `--list-packs` + # prints an empty list, which is the same silent-empty failure the TUI had. + "tirith.packs": ["*/pack.json", "*/policies/*.json"], }, zip_safe=False, classifiers=[ diff --git a/src/tirith/cli.py b/src/tirith/cli.py index f75c9417..1318b86f 100755 --- a/src/tirith/cli.py +++ b/src/tirith/cli.py @@ -5,15 +5,18 @@ import argparse import json import logging +import os import sys import textwrap from tirith.logging import setup_logging -from tirith.prettyprinter import pretty_print_result_dict +from tirith.prettyprinter import pretty_print_policy_set_result, pretty_print_result_dict from tirith.status import ExitStatus from tirith import __version__ +from . import packs from .core import start_policy_evaluation +from .core.core import start_policy_set_evaluation logger = logging.getLogger(__name__) @@ -41,6 +44,46 @@ def eprint(*args, **kwargs): # keep working. SUBCOMMAND = "platform" + +def collect_policy_paths(policy_path, pack_names): + """ + Every policy to run, as (name, path) pairs, in the order they were asked for. + + `name` is what the result reports each policy as: the path relative to the directory that + was given, or `/` for a packed one. Relative, so a report does not depend on + where the run happened. + """ + collected = [] + for name in pack_names: + pack = packs.resolve_pack(name) + if pack is None: + raise ValueError(f"unknown pack '{name}'. Run `tirith --list-packs` to see what is available.") + collected += packs.pack_policy_paths(pack) + + if policy_path and os.path.isdir(policy_path): + for dirpath, dirnames, filenames in os.walk(policy_path): + # Prune in place so os.walk does not descend into hidden directories at all. + dirnames[:] = sorted(d for d in dirnames if not d.startswith(".")) + for filename in sorted(filenames): + if filename.endswith(".json") and not filename.startswith("."): + full = os.path.join(dirpath, filename) + collected.append((os.path.relpath(full, policy_path), full)) + elif policy_path: + collected.append((os.path.basename(policy_path), policy_path)) + + return collected + + +def print_pack_listing(): + installed = packs.list_packs() + if not installed: + print("No policy packs are bundled with this installation.") + return + width = max(len(pack.name) for pack in installed) + for pack in installed: + print(f"{pack.name:{width}} {pack.count:>5} policies {pack.description}") + + # `ui` joins it on the same terms: dispatched before the flat parser, so the local-evaluation # surface and its golden-file output are untouched. It is an optional extra -- it needs Python # 3.9 and tirith supports 3.8 -- so tui/cli.py reports the missing extra rather than failing on @@ -104,7 +147,22 @@ def __init__(self, prog="PROG") -> None: metavar="PATH", type=str, dest="policyPath", - help="Path containing Tirith policy as code", + help="Path to a Tirith policy file, or a directory of them", + ) + parser.add_argument( + "--pack", + metavar="NAME", + type=str, + default=[], + action="append", + dest="packs", + help="Bundled policy pack(s) to run. Repeatable, and combines with -policy-path.", + ) + parser.add_argument( + "--list-packs", + dest="listPacks", + action="store_true", + help="List the policy packs bundled with this installation and exit", ) parser.add_argument( "-input-path", @@ -157,7 +215,17 @@ def __init__(self, prog="PROG") -> None: parser.print_help() sys.exit(0) - if not args.policyPath: + if args.listPacks: + print_pack_listing() + return ExitStatus.SUCCESS + + for pack_name in args.packs: + if packs.resolve_pack(pack_name) is None: + eprint(f"Unknown policy pack '{pack_name}'") + eprint("Run `tirith --list-packs` to see the packs bundled with this installation.") + return ExitStatus.ERROR + + if not args.policyPath and not args.packs: eprint("'-policy-path' argument is required") eprint("-policy-path argument is required. Provide a path to SG policy") return ExitStatus.ERROR @@ -174,12 +242,28 @@ def __init__(self, prog="PROG") -> None: else: setup_logging(verbose=args.verbose) + # A single policy file keeps the result document, the printer and the exit codes it has + # always had -- tests/core/test_output_compatibility.py pins those bytes. A directory or a + # --pack is a *set*, and gets the aggregate document instead. The shape follows how the run + # was asked for, not how many policies matched, so a directory holding one policy still + # reports as a set. + is_set = bool(args.packs) or (args.policyPath and os.path.isdir(args.policyPath)) + try: - result = start_policy_evaluation(args.policyPath, args.inputPath, args.varPaths, args.inlineVars) + if is_set: + policy_paths = collect_policy_paths(args.policyPath, args.packs) + if not policy_paths: + eprint("No policies found to evaluate") + return ExitStatus.ERROR + result = start_policy_set_evaluation(policy_paths, args.inputPath, args.varPaths, args.inlineVars) + else: + result = start_policy_evaluation(args.policyPath, args.inputPath, args.varPaths, args.inlineVars) if args.json: formatted_result = json.dumps(result, indent=3) print(formatted_result) + elif is_set: + pretty_print_policy_set_result(result, verbose=args.verbose) else: pretty_print_result_dict(result) @@ -219,6 +303,13 @@ def __init__(self, prog="PROG") -> None: # an ordinary failed evaluator with no error attached, so it is indistinguishable from a # violation here and exits 3. Fixing that means the engine reporting it distinctly, not this # branch guessing from free text. + # + # A set run reads the same tri-state off `final_result`, which the set runner has + # already rolled up: any policy that said no makes the set False, and `None` means + # nothing reached a verdict at all. The one thing that is deliberately *not* a + # failure is a policy that skipped, because for a pack of any size that is the normal + # case -- most checks do not apply to most plans -- and counting them would make every + # pack run red regardless of the infrastructure. if args.failOnError: final_result = result.get("final_result") if "final_result" not in result or final_result is None: diff --git a/src/tirith/core/core.py b/src/tirith/core/core.py index 81e25147..d8c628c8 100644 --- a/src/tirith/core/core.py +++ b/src/tirith/core/core.py @@ -135,7 +135,13 @@ def generate_evaluator_result(evaluator_obj, input_data, provider_module): # Mark as skipped evaluation err_result.update(dict(passed=None)) evaluation_results.append(err_result) - has_evaluation_passed = None + # A skip says "nothing to inspect here". It must not erase a `False` a sibling + # input already produced: the order the provider emits resources is not part of + # the policy, and an unconditional assignment here made the verdict depend on it. + # A plan whose first matching resource fails and whose second is a tolerated miss + # reported `None` (exit 1) instead of the failure (exit 3). + if has_evaluation_passed is not False: + has_evaluation_passed = None continue evaluation_result = evaluator_instance.evaluate(evaluator_input["value"], evaluator_data) @@ -308,6 +314,19 @@ def start_policy_evaluation( policy_data = json.load(f) # TODO: validate policy_data against schema + input_data = _load_input(input_path) + merged_var_dict = _load_vars(var_paths, inline_vars) + + return start_policy_evaluation_from_dict(policy_data, input_data, merged_var_dict) + + +def _load_input(input_path: str): + """ + Read and parse the input document. + + :param input_path: Path to the input file; parsed as YAML for .yaml/.yml, JSON otherwise + :return: The parsed document + """ with open(input_path) as f: if input_path.endswith(".yaml") or input_path.endswith(".yml"): input_data = list(yaml.safe_load_all(f)) @@ -316,9 +335,20 @@ def start_policy_evaluation( else: input_data = json.load(f) # TODO: validate input_data using the optionally available validate function in provider + return input_data + +def _load_vars(var_paths: List[str], inline_vars: List[str]) -> dict: + """ + Merge every variable file, then every inline `-var name=json`, into one dictionary. + + Later sources win, so an inline variable overrides the same name read from a file. + + :param var_paths: List of paths to the variable files + :param inline_vars: List of `name=` strings + :return: A merged dictionary + """ # TODO: Move this logic into another module - # Merge policy variables into one dictionary var_dicts = [] for var_path in var_paths: with open(var_path, encoding="utf-8") as f: @@ -337,7 +367,78 @@ def start_policy_evaluation( else: logger.error(f"Invalid inline variable: {inline_var}") - return start_policy_evaluation_from_dict(policy_data, input_data, merged_var_dict) + return merged_var_dict + + +def start_policy_set_evaluation( + policy_paths: List[Tuple[str, str]], + input_path: str, + var_paths: List[str] = [], + inline_vars: List[str] = [], +) -> Dict: + """ + Evaluate many policies against one input document, and roll their verdicts up into one. + + The input document and the variables are read once and shared, so running a pack of a + thousand policies parses the plan once rather than a thousand times. + + Each policy keeps its own result document unchanged -- a set run is the single-policy result + repeated, plus a summary -- so anything that already reads a tirith result can read one + element of `policies` without knowing it came from a set. + + `skipped` is a first-class outcome and deliberately not a failure. A policy whose resource + type is absent from the input returns `final_result: None`, and for any pack worth running + that is the *modal* outcome: most checks do not apply to most plans. Counting those as + errors would make every pack run red regardless of the infrastructure. + + :param policy_paths: (name, path) pairs; `name` is what the result reports the policy as + :param input_path: Path to the input file + :param var_paths: List of paths to the variable files + :param inline_vars: List of `name=` strings + :return: {"summary": {...}, "final_result": True|False|None, "policies": [...]} + """ + input_data = _load_input(input_path) + merged_var_dict = _load_vars(var_paths, inline_vars) + + results = [] + counts = {"total": 0, "passed": 0, "failed": 0, "skipped": 0, "errored": 0} + + for name, path in policy_paths: + counts["total"] += 1 + try: + with open(path) as f: + policy_data = json.load(f) + result = start_policy_evaluation_from_dict(policy_data, input_data, merged_var_dict) + except Exception as exc: # noqa: BLE001 - a broken policy is a result we want to report + # One unreadable policy must not take the run down with it: a pack is shipped + # content, and the useful answer is "these 999 ran, this one is broken". + logger.error(f"Could not evaluate policy '{name}': {exc}") + counts["errored"] += 1 + results.append({"policy": name, "errors": [f"{type(exc).__name__}: {exc}"]}) + continue + + final_result = result.get("final_result") + if "final_result" not in result: + # The missing-variables path returns `errors` and no result at all. + counts["errored"] += 1 + elif final_result is True: + counts["passed"] += 1 + elif final_result is False: + counts["failed"] += 1 + else: + counts["skipped"] += 1 + + results.append(dict(policy=name, **result)) + + if counts["failed"]: + set_result = False + elif counts["passed"]: + set_result = True + else: + # Nothing ran, or nothing that ran reached a verdict. Not a pass. + set_result = None + + return {"summary": counts, "final_result": set_result, "policies": results} def _merge_var_dicts(var_dicts: List[dict]) -> dict: diff --git a/src/tirith/packs/__init__.py b/src/tirith/packs/__init__.py new file mode 100644 index 00000000..c35a4825 --- /dev/null +++ b/src/tirith/packs/__init__.py @@ -0,0 +1,112 @@ +""" +Predefined policy packs that ship inside tirith. + +A pack is a directory holding a `pack.json` manifest and a `policies/` directory of ordinary +tirith policy documents. Nothing about a packed policy is special -- each one runs through +`start_policy_evaluation_from_dict` exactly as a file passed with `-policy-path` does. The pack +is only a name for a set, so that `--pack terraform-baseline` is a thing a user can type. + +Located by walking up from this file rather than through `importlib.resources`: `files()` is +3.9+ and setup.py declares `python_requires=">=3.8"`. `tui/examples.py` locates its bundled +examples the same way, for the same reason. + +Every lookup degrades rather than raising when the directory is missing: a partial install +should list no packs, not crash on startup. `setup.py`'s `package_data` and `MANIFEST.in` are +what actually put the files in the distribution, and both have been wrong before. +""" + +import json +import os +from typing import Dict, List, NamedTuple, Optional, Tuple + +PACKS_DIR = os.path.dirname(os.path.abspath(__file__)) + +MANIFEST_NAME = "pack.json" +POLICIES_DIRNAME = "policies" + + +class Pack(NamedTuple): + """A bundled pack, as read from its manifest.""" + + name: str + description: str + path: str + manifest: Dict + + @property + def count(self) -> int: + """How many policies the manifest claims. `policy_paths` is the authority on disk.""" + return self.manifest.get("count", len(self.manifest.get("policies", []))) + + +def _read_manifest(pack_dir: str) -> Optional[Dict]: + manifest_path = os.path.join(pack_dir, MANIFEST_NAME) + if not os.path.isfile(manifest_path): + return None + try: + with open(manifest_path, encoding="utf-8") as f: + manifest = json.load(f) + except (OSError, ValueError): + return None + return manifest if isinstance(manifest, dict) else None + + +def _load_one(name: str) -> Optional[Pack]: + pack_dir = os.path.join(PACKS_DIR, name) + manifest = _read_manifest(pack_dir) + if manifest is None: + return None + return Pack( + name=manifest.get("name", name), + description=manifest.get("description", ""), + path=pack_dir, + manifest=manifest, + ) + + +def list_packs() -> List[Pack]: + """Every bundled pack, ordered by directory name. Empty when none are installed.""" + if not os.path.isdir(PACKS_DIR): + return [] + + found = [] + for key in sorted(os.listdir(PACKS_DIR)): + if key.startswith(".") or key.startswith("__"): + continue + if not os.path.isdir(os.path.join(PACKS_DIR, key)): + continue + pack = _load_one(key) + if pack is not None: + found.append(pack) + return found + + +def resolve_pack(name: str) -> Optional[Pack]: + """The pack called `name`, or None if no such pack is installed.""" + # Matched on the directory name and on the manifest's own `name`, which are expected to + # agree; the manifest wins if they ever do not, because that is what --list-packs prints. + direct = _load_one(name) + if direct is not None: + return direct + for pack in list_packs(): + if pack.name == name: + return pack + return None + + +def pack_policy_paths(pack: Pack) -> List[Tuple[str, str]]: + """ + (name, path) pairs for every policy in `pack`, ordered by filename. + + Read from disk rather than from the manifest's `policies` list: the files are what runs, and + a manifest that has drifted from them should not silently skip a check. `tests/packs` + asserts the two agree. + """ + policies_dir = os.path.join(pack.path, POLICIES_DIRNAME) + if not os.path.isdir(policies_dir): + return [] + return [ + (f"{pack.name}/{fname}", os.path.join(policies_dir, fname)) + for fname in sorted(os.listdir(policies_dir)) + if fname.endswith(".json") + ] diff --git a/src/tirith/packs/terraform-baseline/pack.json b/src/tirith/packs/terraform-baseline/pack.json new file mode 100644 index 00000000..c9b77570 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/pack.json @@ -0,0 +1,1159 @@ +{ + "name": "terraform-baseline", + "description": "Baseline security and configuration checks for Terraform plans", + "tier": "confirmed", + "source": { + "repo": "StackGuardian/tirith-policy-corpus", + "commit": "3cfba37d3fa1520a66c6bcd35ffce4ceb853efbc" + }, + "required_providers": [ + "stackguardian/terraform_plan" + ], + "count": 104, + "policies": [ + { + "id": "SG_TF_0001", + "path": "policies/SG_TF_0001_alicloud_kms_key_automatic_rotation.json", + "name": "Ensure KMS Key Rotation is enabled", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:alicloud", + "encryption" + ] + }, + { + "id": "SG_TF_0002", + "path": "policies/SG_TF_0002_alicloud_disk_encrypted.json", + "name": "Ensure disk is encrypted", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:alicloud", + "encryption" + ] + }, + { + "id": "SG_TF_0003", + "path": "policies/SG_TF_0003_alicloud_ram_account_password_policy_minimum_length.json", + "name": "Ensure RAM password policy requires minimum length of 14 or greater", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:alicloud", + "iam" + ] + }, + { + "id": "SG_TF_0004", + "path": "policies/SG_TF_0004_alicloud_ram_account_password_policy_max_age.json", + "name": "Ensure RAM password policy expires passwords within 90 days or less", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:alicloud", + "iam" + ] + }, + { + "id": "SG_TF_0005", + "path": "policies/SG_TF_0005_alicloud_ram_account_password_policy_require_uppercase_characters.json", + "name": "Ensure RAM password policy requires at least one uppercase letter", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:alicloud", + "iam" + ] + }, + { + "id": "SG_TF_0006", + "path": "policies/SG_TF_0006_aws_ami_launch_permission_count.json", + "name": "Ensure to Limit AMI launch Permissions", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + { + "id": "SG_TF_0007", + "path": "policies/SG_TF_0007_aws_lb_desync_mitigation_mode.json", + "name": "Ensure that ALB is configured with defensive or strictest desync mitigation mode", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "networking" + ] + }, + { + "id": "SG_TF_0008", + "path": "policies/SG_TF_0008_aws_appsync_api_cache_transit_encryption_enabled.json", + "name": "Ensure AppSync API Cache is encrypted in transit", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0009", + "path": "policies/SG_TF_0009_aws_appflow_flow_kms_arn.json", + "name": "Ensure AppFlow flow uses CMK", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0010", + "path": "policies/SG_TF_0010_aws_bedrockagent_agent_guardrail_configuration_identifier.json", + "name": "Ensure AWS Bedrock agent is associated with Bedrock guardrails", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "ai_and_ml" + ] + }, + { + "id": "SG_TF_0011", + "path": "policies/SG_TF_0011_aws_athena_workgroup_configuration_enforce.json", + "name": "Ensure Athena Workgroup should enforce configuration to prevent client disabling encryption", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + { + "id": "SG_TF_0012", + "path": "policies/SG_TF_0012_aws_codepipeline_artifact_store_encryption_key_id.json", + "name": "Ensure CodePipeline Artifact store is using a KMS CMK", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0013", + "path": "policies/SG_TF_0013_aws_codebuild_project_logs_config_s3_encryption_disabled.json", + "name": "Ensure that CodeBuild S3 logs are encrypted", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0014", + "path": "policies/SG_TF_0014_aws_default_vpc_count.json", + "name": "Ensure no default VPC is planned to be provisioned", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "networking" + ] + }, + { + "id": "SG_TF_0015", + "path": "policies/SG_TF_0015_aws_db_security_group_count.json", + "name": "Ensure no aws_db_security_group resources exist", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "networking" + ] + }, + { + "id": "SG_TF_0016", + "path": "policies/SG_TF_0016_aws_db_instance_auto_minor_version_upgrade.json", + "name": "Ensure DB instance gets all minor upgrades automatically", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0017", + "path": "policies/SG_TF_0017_aws_dms_replication_instance_publicly_accessible.json", + "name": "DMS replication instance should not be publicly accessible", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "networking" + ] + }, + { + "id": "SG_TF_0018", + "path": "policies/SG_TF_0018_aws_ebs_snapshot_copy_kms_key_id.json", + "name": "Ensure EBS Snapshot Copy is encrypted by KMS using a customer managed Key (CMK)", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0019", + "path": "policies/SG_TF_0019_aws_ec2_transit_gateway_auto_accept_shared_attachments.json", + "name": "Ensure Transit Gateways do not automatically accept VPC attachment requests", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + { + "id": "SG_TF_0020", + "path": "policies/SG_TF_0020_aws_elasticache_security_group_count.json", + "name": "Ensure no aws_elasticache_security_group resources exist", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "networking" + ] + }, + { + "id": "SG_TF_0021", + "path": "policies/SG_TF_0021_aws_eks_cluster_version.json", + "name": "Ensure EKS clusters run on a supported Kubernetes version", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "kubernetes" + ] + }, + { + "id": "SG_TF_0022", + "path": "policies/SG_TF_0022_aws_elasticache_cluster_subnet_group_name.json", + "name": "Ensure ElastiCache clusters do not use the default subnet group", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "networking" + ] + }, + { + "id": "SG_TF_0023", + "path": "policies/SG_TF_0023_aws_iam_policy_name.json", + "name": "Ensure AWS Managed IAMFullAccess IAM policy is not used.", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "iam" + ] + }, + { + "id": "SG_TF_0024", + "path": "policies/SG_TF_0024_aws_glue_crawler_security_configuration.json", + "name": "Ensure Glue component has a security configuration associated", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0025", + "path": "policies/SG_TF_0025_aws_iam_user_count.json", + "name": "Ensure access is controlled through SSO and not AWS IAM defined users", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "iam" + ] + }, + { + "id": "SG_TF_0026", + "path": "policies/SG_TF_0026_aws_iam_access_key_user.json", + "name": "Ensure IAM root user does not have Access keys", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "iam" + ] + }, + { + "id": "SG_TF_0027", + "path": "policies/SG_TF_0027_aws_instance_metadata_options_http_tokens.json", + "name": "Ensure Instance Metadata Service Version 1 is not enabled", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + { + "id": "SG_TF_0028", + "path": "policies/SG_TF_0028_aws_instance_root_block_device_encrypted.json", + "name": "Ensure all data stored in the Launch configuration or instance Elastic Blocks Store is securely encrypted", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0029", + "path": "policies/SG_TF_0029_aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled.json", + "name": "Ensure Kinesis Firehose delivery stream is encrypted", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0030", + "path": "policies/SG_TF_0030_aws_kendra_index_server_side_encryption_configuration_kms_key_id.json", + "name": "Ensure Kendra index Server side encryption uses CMK", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0031", + "path": "policies/SG_TF_0031_aws_memorydb_cluster_kms_key_arn.json", + "name": "Ensure MemoryDB is encrypted at rest using KMS CMKs", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0032", + "path": "policies/SG_TF_0032_aws_lambda_permission_principal.json", + "name": "Ensure that AWS Lambda function is not publicly accessible", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + { + "id": "SG_TF_0033", + "path": "policies/SG_TF_0033_aws_lambda_function_runtime.json", + "name": "Ensure Lambda Runtime is not deprecated", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + { + "id": "SG_TF_0034", + "path": "policies/SG_TF_0034_aws_mwaa_environment_logging_configuration_worker_logs_enabled.json", + "name": "Ensure MWAA environment has worker logs enabled", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "logging" + ] + }, + { + "id": "SG_TF_0035", + "path": "policies/SG_TF_0035_aws_neptune_cluster_backup_retention_period.json", + "name": "Ensure that Neptune DB cluster has automated backups enabled with adequate retention", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "backup_and_recovery" + ] + }, + { + "id": "SG_TF_0036", + "path": "policies/SG_TF_0036_aws_redshift_cluster_publicly_accessible.json", + "name": "Redshift cluster should not be publicly accessible", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "networking" + ] + }, + { + "id": "SG_TF_0037", + "path": "policies/SG_TF_0037_aws_s3_bucket_object_lock_configuration_enabled.json", + "name": "Ensure that S3 bucket has lock configuration enabled by default", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + { + "id": "SG_TF_0038", + "path": "policies/SG_TF_0038_aws_s3_object_copy_kms_key_id.json", + "name": "Ensure S3 Object Copy is encrypted by KMS using a customer managed Key (CMK)", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0039", + "path": "policies/SG_TF_0039_aws_s3_bucket_object_kms_key_id.json", + "name": "Ensure S3 bucket Object is encrypted by KMS using a customer managed Key (CMK)", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0040", + "path": "policies/SG_TF_0040_aws_sagemaker_notebook_instance_root_access.json", + "name": "Ensure SageMaker Users should not have root access to SageMaker notebook instances", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + { + "id": "SG_TF_0041", + "path": "policies/SG_TF_0041_aws_sagemaker_data_quality_job_definition_output_config_kms_key_id.json", + "name": "Ensure Amazon Sagemaker Data Quality Job uses KMS to encrypt model artifacts", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0042", + "path": "policies/SG_TF_0042_aws_sagemaker_notebook_instance_metadata_service_configuration_minimum.json", + "name": "Ensure Amazon SageMaker Notebook Instance only allows for IMDSv2", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0043", + "path": "policies/SG_TF_0043_aws_sns_topic_kms_master_key_id.json", + "name": "Ensure all data stored in the SNS topic is encrypted", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0044", + "path": "policies/SG_TF_0044_aws_ses_configuration_set_delivery_options_tls_policy.json", + "name": "Ensure SES Configuration Set enforces TLS usage", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "networking" + ] + }, + { + "id": "SG_TF_0045", + "path": "policies/SG_TF_0045_aws_sagemaker_endpoint_configuration_kms_key_arn.json", + "name": "Ensure all data stored in the Sagemaker Endpoint is securely encrypted at rest", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0046", + "path": "policies/SG_TF_0046_aws_workspaces_workspace_root_volume_encryption_enabled.json", + "name": "Ensure that Workspace root volumes are encrypted", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + { + "id": "SG_TF_0047", + "path": "policies/SG_TF_0047_azurerm_automation_account_public_network_access_enabled.json", + "name": "Ensure Azure automation account does NOT have overly permissive network access", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + { + "id": "SG_TF_0048", + "path": "policies/SG_TF_0048_azurerm_automation_account_identity_type.json", + "name": "Ensure Azure automation account is configured with managed identity", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "iam" + ] + }, + { + "id": "SG_TF_0049", + "path": "policies/SG_TF_0049_azurerm_api_management_security_enable_backend_ssl30.json", + "name": "Ensure API management uses at least TLS 1.2", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "encryption" + ] + }, + { + "id": "SG_TF_0050", + "path": "policies/SG_TF_0050_azurerm_app_service_site_config_cors_allowed_origins.json", + "name": "Ensure that CORS disallows every resource to access app services", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + { + "id": "SG_TF_0051", + "path": "policies/SG_TF_0051_azurerm_app_service_storage_account_type.json", + "name": "Ensure that app services use Azure Files", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + { + "id": "SG_TF_0052", + "path": "policies/SG_TF_0052_azurerm_container_registry_sku.json", + "name": "Ensure geo-replicated container registries to match multi-region container deployments.", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "networking" + ] + }, + { + "id": "SG_TF_0053", + "path": "policies/SG_TF_0053_azurerm_container_registry_quarantine_policy_enabled.json", + "name": "Ensure container image quarantine, scan, and mark images verified", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "supply_chain" + ] + }, + { + "id": "SG_TF_0054", + "path": "policies/SG_TF_0054_azurerm_data_factory_public_network_enabled.json", + "name": "Ensure that Azure Data factory public network access is disabled", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "networking" + ] + }, + { + "id": "SG_TF_0055", + "path": "policies/SG_TF_0055_azurerm_container_group_subnet_ids.json", + "name": "Ensure that Azure Container group is deployed into virtual network", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "networking" + ] + }, + { + "id": "SG_TF_0056", + "path": "policies/SG_TF_0056_azurerm_frontdoor_frontend_endpoint_web_application_firewall_policy_li.json", + "name": "Ensure that Azure Front Door enables WAF", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "networking" + ] + }, + { + "id": "SG_TF_0057", + "path": "policies/SG_TF_0057_azurerm_eventgrid_topic_identity_type.json", + "name": "Ensure that Managed identity provider is enabled for Azure Event Grid Topic", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "iam" + ] + }, + { + "id": "SG_TF_0058", + "path": "policies/SG_TF_0058_azurerm_eventhub_namespace_location.json", + "name": "Ensure the Azure Event Hub Namespace is zone redundant", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "backup_and_recovery" + ] + }, + { + "id": "SG_TF_0059", + "path": "policies/SG_TF_0059_azurerm_iothub_public_network_access_enabled.json", + "name": "Ensure that Azure IoT Hub disables public network access", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "networking" + ] + }, + { + "id": "SG_TF_0060", + "path": "policies/SG_TF_0060_azurerm_kubernetes_cluster_default_node_pool_max_pods.json", + "name": "Ensure Azure Kubernetes Cluster (AKS) nodes should use a minimum number of 50 pods.", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "kubernetes" + ] + }, + { + "id": "SG_TF_0061", + "path": "policies/SG_TF_0061_azurerm_kusto_cluster_identity_type.json", + "name": "Ensure that data explorer/Kusto uses managed identities to access Azure resources securely.", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "iam" + ] + }, + { + "id": "SG_TF_0062", + "path": "policies/SG_TF_0062_azurerm_monitor_log_profile_categories.json", + "name": "Ensure audit profile captures all the activities", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "logging" + ] + }, + { + "id": "SG_TF_0063", + "path": "policies/SG_TF_0063_azurerm_network_interface_enable_ip_forwarding.json", + "name": "Ensure that Network Interfaces disable IP forwarding", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "networking" + ] + }, + { + "id": "SG_TF_0064", + "path": "policies/SG_TF_0064_azurerm_search_service_public_network_access_enabled.json", + "name": "Ensure that Azure Cognitive Search disables public network access", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "networking" + ] + }, + { + "id": "SG_TF_0065", + "path": "policies/SG_TF_0065_azurerm_search_service_replica_count.json", + "name": "Ensure that Azure Cognitive Search maintains SLA for search index queries", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + { + "id": "SG_TF_0066", + "path": "policies/SG_TF_0066_azurerm_service_fabric_cluster_azure_active_directory_tenant_id.json", + "name": "Ensures that Active Directory is used for authentication for Service Fabric", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + { + "id": "SG_TF_0067", + "path": "policies/SG_TF_0067_azurerm_service_plan_worker_count.json", + "name": "Ensure App Service has a minimum number of instances for failover", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + { + "id": "SG_TF_0068", + "path": "policies/SG_TF_0068_azurerm_service_plan_zone_balancing_enabled.json", + "name": "Ensure the App Service Plan is zone redundant", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "backup_and_recovery" + ] + }, + { + "id": "SG_TF_0069", + "path": "policies/SG_TF_0069_azurerm_security_center_contact_alerts_to_admins.json", + "name": "Ensure that 'Send email notification for high severity alerts' is set to 'On'", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + { + "id": "SG_TF_0070", + "path": "policies/SG_TF_0070_azurerm_servicebus_namespace_customer_managed_key_infrastructure_encry.json", + "name": "Ensure that Azure Service Bus uses double encryption", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "encryption" + ] + }, + { + "id": "SG_TF_0071", + "path": "policies/SG_TF_0071_azurerm_virtual_machine_storage_os_disk_managed_type.json", + "name": "Ensure Virtual Machines are utilizing Managed Disks", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + { + "id": "SG_TF_0072", + "path": "policies/SG_TF_0072_azurerm_web_application_firewall_policy_settings_enabled.json", + "name": "Ensure that Application Gateway uses WAF in \"Detection\" or \"Prevention\" modes", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:azure", + "networking" + ] + }, + { + "id": "SG_TF_0073", + "path": "policies/SG_TF_0073_digitalocean_firewall_inbound_rule_source_addresses.json", + "name": "Ensure the firewall ingress is not wide open", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:digitalocean", + "networking" + ] + }, + { + "id": "SG_TF_0074", + "path": "policies/SG_TF_0074_google_bigquery_table_deletion_protection.json", + "name": "Ensure BigQuery tables have deletion protection enabled", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "general_security" + ] + }, + { + "id": "SG_TF_0075", + "path": "policies/SG_TF_0075_google_bigquery_table_encryption_configuration_kms_key_name.json", + "name": "Ensure Big Query Tables are encrypted with Customer Supplied Encryption Keys (CSEK)", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + { + "id": "SG_TF_0076", + "path": "policies/SG_TF_0076_google_artifact_registry_repository_kms_key_name.json", + "name": "Ensure Artifact Registry Repositories are encrypted with Customer Supplied Encryption Keys (CSEK)", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + { + "id": "SG_TF_0077", + "path": "policies/SG_TF_0077_google_compute_disk_encryption_key.json", + "name": "Ensure VM disks for critical VMs are encrypted with Customer Supplied Encryption Keys (CSEK)", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + { + "id": "SG_TF_0078", + "path": "policies/SG_TF_0078_google_compute_instance_shielded_config.json", + "name": "Ensure Compute instances are launched with Shielded VM enabled", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "general_security" + ] + }, + { + "id": "SG_TF_0079", + "path": "policies/SG_TF_0079_google_container_cluster_logging_service.json", + "name": "Ensure Stackdriver Logging is set to Enabled on Kubernetes Engine Clusters", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "kubernetes" + ] + }, + { + "id": "SG_TF_0080", + "path": "policies/SG_TF_0080_google_container_cluster_private_config.json", + "name": "Ensure Kubernetes Cluster is created with Private cluster enabled", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "kubernetes" + ] + }, + { + "id": "SG_TF_0081", + "path": "policies/SG_TF_0081_google_document_ai_warehouse_location_kms_key.json", + "name": "Ensure Document AI Warehouse Location is configured to use a Customer Managed Key (CMK)", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + { + "id": "SG_TF_0082", + "path": "policies/SG_TF_0082_google_notebooks_instance_kms_key.json", + "name": "Ensure Vertex AI instance disks are encrypted with a Customer Managed Key (CMK)", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + { + "id": "SG_TF_0083", + "path": "policies/SG_TF_0083_google_kms_crypto_key_iam_member.json", + "name": "Ensure KMS policy should not allow public access", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "iam" + ] + }, + { + "id": "SG_TF_0084", + "path": "policies/SG_TF_0084_google_notebooks_instance_no_public_ip.json", + "name": "Ensure Vertex AI instances are private", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "general_security" + ] + }, + { + "id": "SG_TF_0085", + "path": "policies/SG_TF_0085_google_spanner_database_enable_drop_protection.json", + "name": "Ensure Spanner Database has drop protection enabled", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "general_security" + ] + }, + { + "id": "SG_TF_0086", + "path": "policies/SG_TF_0086_google_spanner_database_encryption_config_kms_key_name.json", + "name": "Ensure Spanner Database is encrypted with Customer Supplied Encryption Keys (CSEK)", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + { + "id": "SG_TF_0087", + "path": "policies/SG_TF_0087_google_storage_bucket_public_access_prevention.json", + "name": "Ensure public access prevention is enforced on Cloud Storage bucket", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "general_security" + ] + }, + { + "id": "SG_TF_0088", + "path": "policies/SG_TF_0088_google_storage_bucket_versioning_enabled.json", + "name": "Ensure Cloud storage has versioning enabled", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:gcp", + "logging" + ] + }, + { + "id": "SG_TF_0089", + "path": "policies/SG_TF_0089_kubernetes_pod_spec_container_env_name.json", + "name": "Do not admit privileged containers", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:kubernetes", + "general_security" + ] + }, + { + "id": "SG_TF_0090", + "path": "policies/SG_TF_0090_kubernetes_pod_spec_container_image_pull_policy.json", + "name": "Image Pull Policy should be Always", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:kubernetes", + "general_security" + ] + }, + { + "id": "SG_TF_0091", + "path": "policies/SG_TF_0091_kubernetes_pod_spec_container_security_context_privileged.json", + "name": "Do not admit privileged containers", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:kubernetes", + "general_security" + ] + }, + { + "id": "SG_TF_0092", + "path": "policies/SG_TF_0092_kubernetes_pod_spec_container_security_context_capabilities_add.json", + "name": "Minimize the admission of containers with added capability", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:kubernetes", + "general_security" + ] + }, + { + "id": "SG_TF_0093", + "path": "policies/SG_TF_0093_kubernetes_service_account_metadata_name.json", + "name": "Ensure that default service accounts are not actively used", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:kubernetes", + "general_security" + ] + }, + { + "id": "SG_TF_0094", + "path": "policies/SG_TF_0094_linode_firewall_inbound_policy.json", + "name": "Ensure Inbound Firewall Policy is not set to ACCEPT", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:linode", + "general_security" + ] + }, + { + "id": "SG_TF_0095", + "path": "policies/SG_TF_0095_oci_file_storage_export_options_identity_squash.json", + "name": "Ensure File Storage File System access is restricted to root users", + "fidelity": "approximate", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:oci", + "general_security" + ] + }, + { + "id": "SG_TF_0096", + "path": "policies/SG_TF_0096_oci_core_instance_launch_options_is_pv_encryption_in_transit_enabled.json", + "name": "Ensure OCI Compute Instance boot volume has in-transit data encryption enabled", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:oci", + "encryption" + ] + }, + { + "id": "SG_TF_0097", + "path": "policies/SG_TF_0097_oci_identity_authentication_policy_password_is_lowercase_characters_re.json", + "name": "OCI IAM password policy - must contain lower case", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:oci", + "general_security" + ] + }, + { + "id": "SG_TF_0098", + "path": "policies/SG_TF_0098_panos_ipsec_crypto_profile_protocol.json", + "name": "Ensure IPsec profiles do not specify use of insecure protocols", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:panos", + "networking" + ] + }, + { + "id": "SG_TF_0099", + "path": "policies/SG_TF_0099_panos_management_profile_telnet.json", + "name": "Ensure plain-text management Telnet is not enabled for an Interface Management Profile", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:panos", + "networking" + ] + }, + { + "id": "SG_TF_0100", + "path": "policies/SG_TF_0100_tencentcloud_clb_listener_protocol.json", + "name": "Ensure Tencent Cloud CLBs use modern, encrypted protocols", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:tencentcloud", + "networking" + ] + }, + { + "id": "SG_TF_0101", + "path": "policies/SG_TF_0101_tencentcloud_cbs_storage_encrypt.json", + "name": "Ensure Tencent Cloud CBS is encrypted", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:tencentcloud", + "encryption" + ] + }, + { + "id": "SG_TF_0102", + "path": "policies/SG_TF_0102_tencentcloud_instance_disable_monitor_service.json", + "name": "Ensure Tencent Cloud CVM monitor service is enabled", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:tencentcloud", + "logging" + ] + }, + { + "id": "SG_TF_0103", + "path": "policies/SG_TF_0103_yandex_kubernetes_cluster_master_public_ip.json", + "name": "Ensure Kubernetes cluster does not have public IP address.", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:yandex", + "networking" + ] + }, + { + "id": "SG_TF_0104", + "path": "policies/SG_TF_0104_yandex_kms_symmetric_key_rotation_period.json", + "name": "Ensure KMS symmetric key is rotated.", + "fidelity": "exact", + "required_provider": "stackguardian/terraform_plan", + "tags": [ + "cloud:yandex", + "encryption" + ] + } + ] +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0001_alicloud_kms_key_automatic_rotation.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0001_alicloud_kms_key_automatic_rotation.json new file mode 100644 index 00000000..72e56db6 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0001_alicloud_kms_key_automatic_rotation.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0001", + "name": "Ensure KMS Key Rotation is enabled", + "description": "Ensure KMS Key Rotation is enabled", + "tags": [ + "cloud:alicloud", + "encryption" + ] + }, + "evaluators": [ + { + "id": "automatic_rotation_enabled", + "description": "Every alicloud_kms_key sets automatic_rotation = Enabled; an absent value fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "alicloud_kms_key", + "terraform_resource_attribute": "automatic_rotation" + }, + "condition": { + "type": "Equals", + "value": "Enabled", + "error_tolerance": 1 + } + } + ], + "eval_expression": "automatic_rotation_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0002_alicloud_disk_encrypted.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0002_alicloud_disk_encrypted.json new file mode 100644 index 00000000..b0e69086 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0002_alicloud_disk_encrypted.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0002", + "name": "Ensure disk is encrypted", + "description": "Ensure disk is encrypted", + "tags": [ + "cloud:alicloud", + "encryption" + ] + }, + "evaluators": [ + { + "id": "disk_encrypted", + "description": "Every alicloud_disk sets encrypted = true; an absent or null encrypted fails. A disk restored from a snapshot inherits the snapshot's encryption, which this check cannot scope on and so still requires the flag.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "alicloud_disk", + "terraform_resource_attribute": "encrypted" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "disk_encrypted" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0003_alicloud_ram_account_password_policy_minimum_length.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0003_alicloud_ram_account_password_policy_minimum_length.json new file mode 100644 index 00000000..643b2dfe --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0003_alicloud_ram_account_password_policy_minimum_length.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0003", + "name": "Ensure RAM password policy requires minimum length of 14 or greater", + "description": "Ensure RAM password policy requires minimum length of 14 or greater", + "tags": [ + "cloud:alicloud", + "iam" + ] + }, + "evaluators": [ + { + "id": "minimum_password_length_at_least_14", + "description": "alicloud_ram_account_password_policy.minimum_password_length must be 14 or more. A null value never satisfies a numeric comparison, so a policy that omits the attribute fails; the provider default is below 14 and fails too.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "alicloud_ram_account_password_policy", + "terraform_resource_attribute": "minimum_password_length" + }, + "condition": { + "type": "GreaterThanEqualTo", + "value": 14, + "error_tolerance": 1 + } + } + ], + "eval_expression": "minimum_password_length_at_least_14" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0004_alicloud_ram_account_password_policy_max_age.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0004_alicloud_ram_account_password_policy_max_age.json new file mode 100644 index 00000000..624e8e90 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0004_alicloud_ram_account_password_policy_max_age.json @@ -0,0 +1,44 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0004", + "name": "Ensure RAM password policy expires passwords within 90 days or less", + "description": "Ensure RAM password policy expires passwords within 90 days or less", + "tags": [ + "cloud:alicloud", + "iam" + ] + }, + "evaluators": [ + { + "id": "max_password_age_expires", + "description": "alicloud_ram_account_password_policy.max_password_age must be greater than 0, so the provider default of 0 ('never expires') fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "alicloud_ram_account_password_policy", + "terraform_resource_attribute": "max_password_age" + }, + "condition": { + "type": "GreaterThan", + "value": 0, + "error_tolerance": 1 + } + }, + { + "id": "max_password_age_within_90_days", + "description": "alicloud_ram_account_password_policy.max_password_age must be 90 or less. AND-ed with the previous evaluator to express the range 0 < max_age <= 90; both fail on a null value.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "alicloud_ram_account_password_policy", + "terraform_resource_attribute": "max_password_age" + }, + "condition": { + "type": "LessThanEqualTo", + "value": 90, + "error_tolerance": 1 + } + } + ], + "eval_expression": "max_password_age_expires && max_password_age_within_90_days" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0005_alicloud_ram_account_password_policy_require_uppercase_characters.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0005_alicloud_ram_account_password_policy_require_uppercase_characters.json new file mode 100644 index 00000000..fd7d0c9d --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0005_alicloud_ram_account_password_policy_require_uppercase_characters.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0005", + "name": "Ensure RAM password policy requires at least one uppercase letter", + "description": "Ensure RAM password policy requires at least one uppercase letter", + "tags": [ + "cloud:alicloud", + "iam" + ] + }, + "evaluators": [ + { + "id": "require_uppercase_characters_enabled", + "description": "alicloud_ram_account_password_policy.require_uppercase_characters must be true. Boolean attribute, so Equals true rather than IsNotEmpty.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "alicloud_ram_account_password_policy", + "terraform_resource_attribute": "require_uppercase_characters" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "require_uppercase_characters_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0006_aws_ami_launch_permission_count.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0006_aws_ami_launch_permission_count.json new file mode 100644 index 00000000..0ff277b5 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0006_aws_ami_launch_permission_count.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0006", + "name": "Ensure to Limit AMI launch Permissions", + "description": "Ensure to Limit AMI launch Permissions", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + "evaluators": [ + { + "id": "no_ami_launch_permission", + "description": "The plan declares no aws_ami_launch_permission resource", + "provider_args": { + "operation_type": "count", + "terraform_resource_type": "aws_ami_launch_permission" + }, + "condition": { + "type": "Equals", + "value": 0, + "error_tolerance": 1 + } + } + ], + "eval_expression": "no_ami_launch_permission" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0007_aws_lb_desync_mitigation_mode.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0007_aws_lb_desync_mitigation_mode.json new file mode 100644 index 00000000..9a33fb5d --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0007_aws_lb_desync_mitigation_mode.json @@ -0,0 +1,64 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0007", + "name": "Ensure that ALB is configured with defensive or strictest desync mitigation mode", + "description": "Ensure that ALB is configured with defensive or strictest desync mitigation mode", + "tags": [ + "cloud:aws", + "networking" + ] + }, + "evaluators": [ + { + "id": "lb_desync_mode", + "description": "aws_lb desync_mitigation_mode is not monitor", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_lb", + "terraform_resource_attribute": "desync_mitigation_mode" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "monitor" + ], + "error_tolerance": 1 + } + }, + { + "id": "alb_desync_mode", + "description": "aws_alb desync_mitigation_mode is not monitor", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_alb", + "terraform_resource_attribute": "desync_mitigation_mode" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "monitor" + ], + "error_tolerance": 1 + } + }, + { + "id": "elb_desync_mode", + "description": "aws_elb desync_mitigation_mode is not monitor", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_elb", + "terraform_resource_attribute": "desync_mitigation_mode" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "monitor" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "lb_desync_mode && alb_desync_mode && elb_desync_mode" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0008_aws_appsync_api_cache_transit_encryption_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0008_aws_appsync_api_cache_transit_encryption_enabled.json new file mode 100644 index 00000000..00b3524c --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0008_aws_appsync_api_cache_transit_encryption_enabled.json @@ -0,0 +1,31 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0008", + "name": "Ensure AppSync API Cache is encrypted in transit", + "description": "Ensure AppSync API Cache is encrypted in transit", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Set transit_encryption_enabled = true on the aws_appsync_api_cache resource." + }, + "evaluators": [ + { + "id": "transit_encryption_enabled", + "description": "transit_encryption_enabled must be true on every aws_appsync_api_cache", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_appsync_api_cache", + "terraform_resource_attribute": "transit_encryption_enabled" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "transit_encryption_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0009_aws_appflow_flow_kms_arn.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0009_aws_appflow_flow_kms_arn.json new file mode 100644 index 00000000..998fef28 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0009_aws_appflow_flow_kms_arn.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0009", + "name": "Ensure AppFlow flow uses CMK", + "description": "Ensure AppFlow flow uses CMK", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Set kms_arn to a customer managed KMS key ARN on the aws_appflow_flow resource." + }, + "evaluators": [ + { + "id": "kms_arn_set", + "description": "kms_arn must be a non-empty string on every aws_appflow_flow", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_appflow_flow", + "terraform_resource_attribute": "kms_arn" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "kms_arn_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0010_aws_bedrockagent_agent_guardrail_configuration_identifier.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0010_aws_bedrockagent_agent_guardrail_configuration_identifier.json new file mode 100644 index 00000000..42151c4f --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0010_aws_bedrockagent_agent_guardrail_configuration_identifier.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0010", + "name": "Ensure AWS Bedrock agent is associated with Bedrock guardrails", + "description": "Ensure AWS Bedrock agent is associated with Bedrock guardrails", + "tags": [ + "cloud:aws", + "ai_and_ml" + ], + "remediation": "Add a guardrail_configuration block with guardrail_identifier to every aws_bedrockagent_agent." + }, + "evaluators": [ + { + "id": "bedrock_agent_guardrail_identifier_set", + "description": "Every aws_bedrockagent_agent must carry guardrail_configuration.0.guardrail_identifier. The block is a list in the plan, so an absent one is [] in change.after -- a severity-2 miss, which fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_bedrockagent_agent", + "terraform_resource_attribute": "guardrail_configuration.0.guardrail_identifier" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "bedrock_agent_guardrail_identifier_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0011_aws_athena_workgroup_configuration_enforce.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0011_aws_athena_workgroup_configuration_enforce.json new file mode 100644 index 00000000..50850384 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0011_aws_athena_workgroup_configuration_enforce.json @@ -0,0 +1,33 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0011", + "name": "Ensure Athena Workgroup should enforce configuration to prevent client disabling encryption", + "description": "Ensure Athena Workgroup should enforce configuration to prevent client disabling encryption", + "tags": [ + "cloud:aws", + "general_security" + ], + "remediation": "Leave enforce_workgroup_configuration at its default (true) inside the aws_athena_workgroup configuration block, never set it to false." + }, + "evaluators": [ + { + "id": "enforce_workgroup_configuration_not_disabled", + "description": "No aws_athena_workgroup may set configuration.0.enforce_workgroup_configuration to false. A list-valued NotContainedIn passes on an explicit null, and error_tolerance 2 skips a workgroup with no configuration block at all.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_athena_workgroup", + "terraform_resource_attribute": "configuration.0.enforce_workgroup_configuration" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + false + ], + "error_tolerance": 2 + } + } + ], + "eval_expression": "enforce_workgroup_configuration_not_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0012_aws_codepipeline_artifact_store_encryption_key_id.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0012_aws_codepipeline_artifact_store_encryption_key_id.json new file mode 100644 index 00000000..79654d0f --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0012_aws_codepipeline_artifact_store_encryption_key_id.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0012", + "name": "Ensure CodePipeline Artifact store is using a KMS CMK", + "description": "Ensure CodePipeline Artifact store is using a KMS CMK", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Add an encryption_key block with a KMS key id to every artifact_store of every aws_codepipeline." + }, + "evaluators": [ + { + "id": "codepipeline_artifact_store_encryption_key_id_set", + "description": "every aws_codepipeline artifact_store must carry a non-empty encryption_key.id", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_codepipeline", + "terraform_resource_attribute": "artifact_store.*.encryption_key.*.id" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "codepipeline_artifact_store_encryption_key_id_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0013_aws_codebuild_project_logs_config_s3_encryption_disabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0013_aws_codebuild_project_logs_config_s3_encryption_disabled.json new file mode 100644 index 00000000..9d87e752 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0013_aws_codebuild_project_logs_config_s3_encryption_disabled.json @@ -0,0 +1,31 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0013", + "name": "Ensure that CodeBuild S3 logs are encrypted", + "description": "Ensure that CodeBuild S3 logs are encrypted", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Do not set logs_config.s3_logs.encryption_disabled = true on aws_codebuild_project." + }, + "evaluators": [ + { + "id": "codebuild_s3_logs_encryption_not_disabled", + "description": "no aws_codebuild_project may set logs_config.s3_logs.encryption_disabled = true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_codebuild_project", + "terraform_resource_attribute": "logs_config.*.s3_logs.*.encryption_disabled" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 2 + } + } + ], + "eval_expression": "codebuild_s3_logs_encryption_not_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0014_aws_default_vpc_count.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0014_aws_default_vpc_count.json new file mode 100644 index 00000000..617357a3 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0014_aws_default_vpc_count.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0014", + "name": "Ensure no default VPC is planned to be provisioned", + "description": "Ensure no default VPC is planned to be provisioned", + "tags": [ + "cloud:aws", + "networking" + ], + "remediation": "Remove the aws_default_vpc resource and manage an explicit aws_vpc instead." + }, + "evaluators": [ + { + "id": "no_default_vpc", + "description": "The plan must contain zero aws_default_vpc resources", + "provider_args": { + "operation_type": "count", + "terraform_resource_type": "aws_default_vpc" + }, + "condition": { + "type": "Equals", + "value": 0, + "error_tolerance": 1 + } + } + ], + "eval_expression": "no_default_vpc" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0015_aws_db_security_group_count.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0015_aws_db_security_group_count.json new file mode 100644 index 00000000..feed63e4 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0015_aws_db_security_group_count.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0015", + "name": "Ensure no aws_db_security_group resources exist", + "description": "Ensure no aws_db_security_group resources exist", + "tags": [ + "cloud:aws", + "networking" + ], + "remediation": "Delete the aws_db_security_group resource and place the RDS instance in a VPC, controlling access with an aws_security_group instead." + }, + "evaluators": [ + { + "id": "no_db_security_group", + "description": "The plan must contain zero aws_db_security_group resources; DB security groups only apply to RDS instances outside a VPC", + "provider_args": { + "operation_type": "count", + "terraform_resource_type": "aws_db_security_group" + }, + "condition": { + "type": "Equals", + "value": 0, + "error_tolerance": 1 + } + } + ], + "eval_expression": "no_db_security_group" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0016_aws_db_instance_auto_minor_version_upgrade.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0016_aws_db_instance_auto_minor_version_upgrade.json new file mode 100644 index 00000000..236afcc4 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0016_aws_db_instance_auto_minor_version_upgrade.json @@ -0,0 +1,45 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0016", + "name": "Ensure DB instance gets all minor upgrades automatically", + "description": "Ensure DB instance gets all minor upgrades automatically", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Set auto_minor_version_upgrade = true." + }, + "evaluators": [ + { + "id": "db_instance_auto_minor_upgrade", + "description": "aws_db_instance.auto_minor_version_upgrade must be true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_db_instance", + "terraform_resource_attribute": "auto_minor_version_upgrade" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + }, + { + "id": "cluster_instance_auto_minor_upgrade", + "description": "aws_rds_cluster_instance.auto_minor_version_upgrade must be true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_rds_cluster_instance", + "terraform_resource_attribute": "auto_minor_version_upgrade" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "db_instance_auto_minor_upgrade && cluster_instance_auto_minor_upgrade" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0017_aws_dms_replication_instance_publicly_accessible.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0017_aws_dms_replication_instance_publicly_accessible.json new file mode 100644 index 00000000..6d773616 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0017_aws_dms_replication_instance_publicly_accessible.json @@ -0,0 +1,32 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0017", + "name": "DMS replication instance should not be publicly accessible", + "description": "DMS replication instance should not be publicly accessible", + "tags": [ + "cloud:aws", + "networking" + ] + }, + "evaluators": [ + { + "id": "not_publicly_accessible", + "description": "aws_dms_replication_instance.publicly_accessible must not be true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_dms_replication_instance", + "terraform_resource_attribute": "publicly_accessible" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + true + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "not_publicly_accessible" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0018_aws_ebs_snapshot_copy_kms_key_id.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0018_aws_ebs_snapshot_copy_kms_key_id.json new file mode 100644 index 00000000..7a241a3e --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0018_aws_ebs_snapshot_copy_kms_key_id.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0018", + "name": "Ensure EBS Snapshot Copy is encrypted by KMS using a customer managed Key (CMK)", + "description": "Ensure EBS Snapshot Copy is encrypted by KMS using a customer managed Key (CMK)", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + "evaluators": [ + { + "id": "snapshot_copy_kms_key_id_set", + "description": "Every aws_ebs_snapshot_copy names a KMS key; a null or missing kms_key_id fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_ebs_snapshot_copy", + "terraform_resource_attribute": "kms_key_id" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "snapshot_copy_kms_key_id_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0019_aws_ec2_transit_gateway_auto_accept_shared_attachments.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0019_aws_ec2_transit_gateway_auto_accept_shared_attachments.json new file mode 100644 index 00000000..10407c57 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0019_aws_ec2_transit_gateway_auto_accept_shared_attachments.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0019", + "name": "Ensure Transit Gateways do not automatically accept VPC attachment requests", + "description": "Ensure Transit Gateways do not automatically accept VPC attachment requests", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + "evaluators": [ + { + "id": "auto_accept_shared_attachments_not_enable", + "description": "No aws_ec2_transit_gateway sets auto_accept_shared_attachments = \"enable\". A null value passes NotEquals, so a gateway that leaves the argument out keeps the safe provider default.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_ec2_transit_gateway", + "terraform_resource_attribute": "auto_accept_shared_attachments" + }, + "condition": { + "type": "NotEquals", + "value": "enable", + "error_tolerance": 1 + } + } + ], + "eval_expression": "auto_accept_shared_attachments_not_enable" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0020_aws_elasticache_security_group_count.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0020_aws_elasticache_security_group_count.json new file mode 100644 index 00000000..a66da81f --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0020_aws_elasticache_security_group_count.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0020", + "name": "Ensure no aws_elasticache_security_group resources exist", + "description": "Ensure no aws_elasticache_security_group resources exist", + "tags": [ + "cloud:aws", + "networking" + ] + }, + "evaluators": [ + { + "id": "no_elasticache_security_group", + "description": "aws_elasticache_security_group is EC2-Classic only and must not be used", + "provider_args": { + "operation_type": "count", + "terraform_resource_type": "aws_elasticache_security_group" + }, + "condition": { + "type": "Equals", + "value": 0, + "error_tolerance": 1 + } + } + ], + "eval_expression": "no_elasticache_security_group" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0021_aws_eks_cluster_version.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0021_aws_eks_cluster_version.json new file mode 100644 index 00000000..49106b15 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0021_aws_eks_cluster_version.json @@ -0,0 +1,39 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0021", + "name": "Ensure EKS clusters run on a supported Kubernetes version", + "description": "Ensure EKS clusters run on a supported Kubernetes version", + "tags": [ + "cloud:aws", + "kubernetes" + ] + }, + "evaluators": [ + { + "id": "supported_kubernetes_version", + "description": "aws_eks_cluster.version must be a currently supported Kubernetes version (or left unpinned)", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_eks_cluster", + "terraform_resource_attribute": "version" + }, + "condition": { + "type": "ContainedIn", + "value": [ + null, + "1.29", + "1.30", + "1.31", + "1.32", + "1.33", + "1.34", + "1.35" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "supported_kubernetes_version" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0022_aws_elasticache_cluster_subnet_group_name.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0022_aws_elasticache_cluster_subnet_group_name.json new file mode 100644 index 00000000..2ce24971 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0022_aws_elasticache_cluster_subnet_group_name.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0022", + "name": "Ensure ElastiCache clusters do not use the default subnet group", + "description": "Ensure ElastiCache clusters do not use the default subnet group", + "tags": [ + "cloud:aws", + "networking" + ] + }, + "evaluators": [ + { + "id": "subnet_group_name_set", + "description": "Every aws_elasticache_cluster must name a subnet group instead of falling back to the default one", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_elasticache_cluster", + "terraform_resource_attribute": "subnet_group_name" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "subnet_group_name_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0023_aws_iam_policy_name.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0023_aws_iam_policy_name.json new file mode 100644 index 00000000..01759a84 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0023_aws_iam_policy_name.json @@ -0,0 +1,121 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0023", + "name": "Ensure AWS Managed IAMFullAccess IAM policy is not used.", + "description": "Ensure AWS Managed IAMFullAccess IAM policy is not used.", + "tags": [ + "cloud:aws", + "iam" + ], + "remediation": "Replace arn:aws:iam::aws:policy/IAMFullAccess with a customer managed policy that grants only the IAM actions the principal needs." + }, + "evaluators": [ + { + "id": "iam_policy_name_not_iamfullaccess", + "description": "No data.aws_iam_policy resolves the managed policy named IAMFullAccess. error_tolerance 2 skips a policy whose name is unknown at plan time (name_prefix) rather than failing it.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_iam_policy", + "terraform_resource_attribute": "name" + }, + "condition": { + "type": "NotEquals", + "value": "IAMFullAccess", + "error_tolerance": 2 + } + }, + { + "id": "policy_attachment_arn", + "description": "aws_iam_policy_attachment.policy_arn must not be the AWS managed IAMFullAccess policy; NotContainedIn with a list also passes an explicit null, and tolerance 2 skips an ARN that is unknown at plan time", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_iam_policy_attachment", + "terraform_resource_attribute": "policy_arn" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "arn:aws:iam::aws:policy/IAMFullAccess", + "arn:aws-us-gov:iam::aws:policy/IAMFullAccess", + "arn:aws-cn:iam::aws:policy/IAMFullAccess" + ], + "error_tolerance": 2 + } + }, + { + "id": "user_policy_attachment_arn", + "description": "aws_iam_user_policy_attachment.policy_arn must not be the AWS managed IAMFullAccess policy; NotContainedIn with a list also passes an explicit null, and tolerance 2 skips an ARN that is unknown at plan time", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_iam_user_policy_attachment", + "terraform_resource_attribute": "policy_arn" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "arn:aws:iam::aws:policy/IAMFullAccess", + "arn:aws-us-gov:iam::aws:policy/IAMFullAccess", + "arn:aws-cn:iam::aws:policy/IAMFullAccess" + ], + "error_tolerance": 2 + } + }, + { + "id": "role_policy_attachment_arn", + "description": "aws_iam_role_policy_attachment.policy_arn must not be the AWS managed IAMFullAccess policy; NotContainedIn with a list also passes an explicit null, and tolerance 2 skips an ARN that is unknown at plan time", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_iam_role_policy_attachment", + "terraform_resource_attribute": "policy_arn" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "arn:aws:iam::aws:policy/IAMFullAccess", + "arn:aws-us-gov:iam::aws:policy/IAMFullAccess", + "arn:aws-cn:iam::aws:policy/IAMFullAccess" + ], + "error_tolerance": 2 + } + }, + { + "id": "group_policy_attachment_arn", + "description": "aws_iam_group_policy_attachment.policy_arn must not be the AWS managed IAMFullAccess policy; NotContainedIn with a list also passes an explicit null, and tolerance 2 skips an ARN that is unknown at plan time", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_iam_group_policy_attachment", + "terraform_resource_attribute": "policy_arn" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "arn:aws:iam::aws:policy/IAMFullAccess", + "arn:aws-us-gov:iam::aws:policy/IAMFullAccess", + "arn:aws-cn:iam::aws:policy/IAMFullAccess" + ], + "error_tolerance": 2 + } + }, + { + "id": "ssoadmin_managed_policy_arn", + "description": "aws_ssoadmin_managed_policy_attachment.managed_policy_arn must not be the AWS managed IAMFullAccess policy", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_ssoadmin_managed_policy_attachment", + "terraform_resource_attribute": "managed_policy_arn" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "arn:aws:iam::aws:policy/IAMFullAccess", + "arn:aws-us-gov:iam::aws:policy/IAMFullAccess", + "arn:aws-cn:iam::aws:policy/IAMFullAccess" + ], + "error_tolerance": 2 + } + } + ], + "eval_expression": "iam_policy_name_not_iamfullaccess && policy_attachment_arn && user_policy_attachment_arn && role_policy_attachment_arn && group_policy_attachment_arn && ssoadmin_managed_policy_arn" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0024_aws_glue_crawler_security_configuration.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0024_aws_glue_crawler_security_configuration.json new file mode 100644 index 00000000..bebed32a --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0024_aws_glue_crawler_security_configuration.json @@ -0,0 +1,56 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0024", + "name": "Ensure Glue component has a security configuration associated", + "description": "Ensure Glue component has a security configuration associated", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Set security_configuration on every aws_glue_crawler, aws_glue_dev_endpoint and aws_glue_job to the name of an aws_glue_security_configuration." + }, + "evaluators": [ + { + "id": "crawler_security_configuration", + "description": "aws_glue_crawler must carry a non-empty security_configuration; an absent one fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_glue_crawler", + "terraform_resource_attribute": "security_configuration" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + }, + { + "id": "dev_endpoint_security_configuration", + "description": "aws_glue_dev_endpoint must carry a non-empty security_configuration", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_glue_dev_endpoint", + "terraform_resource_attribute": "security_configuration" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + }, + { + "id": "job_security_configuration", + "description": "aws_glue_job must carry a non-empty security_configuration", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_glue_job", + "terraform_resource_attribute": "security_configuration" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "crawler_security_configuration && dev_endpoint_security_configuration && job_security_configuration" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0025_aws_iam_user_count.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0025_aws_iam_user_count.json new file mode 100644 index 00000000..072218ed --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0025_aws_iam_user_count.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0025", + "name": "Ensure access is controlled through SSO and not AWS IAM defined users", + "description": "Ensure access is controlled through SSO and not AWS IAM defined users", + "tags": [ + "cloud:aws", + "iam" + ] + }, + "evaluators": [ + { + "id": "no_iam_users", + "description": "The plan must not create any aws_iam_user; access belongs in SSO", + "provider_args": { + "operation_type": "count", + "terraform_resource_type": "aws_iam_user" + }, + "condition": { + "type": "Equals", + "value": 0, + "error_tolerance": 1 + } + } + ], + "eval_expression": "no_iam_users" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0026_aws_iam_access_key_user.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0026_aws_iam_access_key_user.json new file mode 100644 index 00000000..1aa91325 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0026_aws_iam_access_key_user.json @@ -0,0 +1,32 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0026", + "name": "Ensure IAM root user does not have Access keys", + "description": "Ensure IAM root user does not have Access keys", + "tags": [ + "cloud:aws", + "iam" + ] + }, + "evaluators": [ + { + "id": "access_key_user_not_root", + "description": "aws_iam_access_key.user must not be the root user", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_iam_access_key", + "terraform_resource_attribute": "user" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "root" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "access_key_user_not_root" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0027_aws_instance_metadata_options_http_tokens.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0027_aws_instance_metadata_options_http_tokens.json new file mode 100644 index 00000000..079157ce --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0027_aws_instance_metadata_options_http_tokens.json @@ -0,0 +1,58 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0027", + "name": "Ensure Instance Metadata Service Version 1 is not enabled", + "description": "Ensure Instance Metadata Service Version 1 is not enabled", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + "evaluators": [ + { + "id": "instance_http_tokens_required", + "description": "aws_instance metadata_options.http_tokens must be \"required\"", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_instance", + "terraform_resource_attribute": "metadata_options.0.http_tokens" + }, + "condition": { + "type": "Equals", + "value": "required", + "error_tolerance": 1 + } + }, + { + "id": "launch_template_http_tokens_required", + "description": "aws_launch_template metadata_options.http_tokens must be \"required\"", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_launch_template", + "terraform_resource_attribute": "metadata_options.0.http_tokens" + }, + "condition": { + "type": "Equals", + "value": "required", + "error_tolerance": 1 + } + }, + { + "id": "launch_configuration_http_tokens_required", + "description": "aws_launch_configuration metadata_options.http_tokens must be \"required\"", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_launch_configuration", + "terraform_resource_attribute": "metadata_options.0.http_tokens" + }, + "condition": { + "type": "Equals", + "value": "required", + "error_tolerance": 1 + } + } + ], + "eval_expression": "instance_http_tokens_required && launch_template_http_tokens_required && launch_configuration_http_tokens_required" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0028_aws_instance_root_block_device_encrypted.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0028_aws_instance_root_block_device_encrypted.json new file mode 100644 index 00000000..44e68133 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0028_aws_instance_root_block_device_encrypted.json @@ -0,0 +1,72 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0028", + "name": "Ensure all data stored in the Launch configuration or instance Elastic Blocks Store is securely encrypted", + "description": "Ensure all data stored in the Launch configuration or instance Elastic Blocks Store is securely encrypted", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + "evaluators": [ + { + "id": "instance_root_block_device_not_unencrypted", + "description": "aws_instance must declare a root_block_device and must not set encrypted = false on it", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_instance", + "terraform_resource_attribute": "root_block_device.0.encrypted" + }, + "condition": { + "type": "NotEquals", + "value": false, + "error_tolerance": 1 + } + }, + { + "id": "instance_ebs_block_devices_not_unencrypted", + "description": "No aws_instance ebs_block_device may set encrypted = false", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_instance", + "terraform_resource_attribute": "ebs_block_device.*.encrypted" + }, + "condition": { + "type": "NotEquals", + "value": false, + "error_tolerance": 2 + } + }, + { + "id": "launch_configuration_root_block_device_not_unencrypted", + "description": "aws_launch_configuration must declare a root_block_device and must not set encrypted = false on it", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_launch_configuration", + "terraform_resource_attribute": "root_block_device.0.encrypted" + }, + "condition": { + "type": "NotEquals", + "value": false, + "error_tolerance": 1 + } + }, + { + "id": "launch_configuration_ebs_block_devices_not_unencrypted", + "description": "No aws_launch_configuration ebs_block_device may set encrypted = false", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_launch_configuration", + "terraform_resource_attribute": "ebs_block_device.*.encrypted" + }, + "condition": { + "type": "NotEquals", + "value": false, + "error_tolerance": 2 + } + } + ], + "eval_expression": "instance_root_block_device_not_unencrypted && instance_ebs_block_devices_not_unencrypted && launch_configuration_root_block_device_not_unencrypted && launch_configuration_ebs_block_devices_not_unencrypted" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0029_aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0029_aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled.json new file mode 100644 index 00000000..944d451a --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0029_aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0029", + "name": "Ensure Kinesis Firehose delivery stream is encrypted", + "description": "Ensure Kinesis Firehose delivery stream is encrypted", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + "evaluators": [ + { + "id": "firehose_sse_enabled", + "description": "aws_kinesis_firehose_delivery_stream must set server_side_encryption[0].enabled = true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_kinesis_firehose_delivery_stream", + "terraform_resource_attribute": "server_side_encryption.0.enabled" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "firehose_sse_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0030_aws_kendra_index_server_side_encryption_configuration_kms_key_id.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0030_aws_kendra_index_server_side_encryption_configuration_kms_key_id.json new file mode 100644 index 00000000..05172843 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0030_aws_kendra_index_server_side_encryption_configuration_kms_key_id.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0030", + "name": "Ensure Kendra index Server side encryption uses CMK", + "description": "Ensure Kendra index Server side encryption uses CMK", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + "evaluators": [ + { + "id": "kendra_sse_kms_key_id_set", + "description": "aws_kendra_index must set server_side_encryption_configuration[0].kms_key_id to a customer managed key", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_kendra_index", + "terraform_resource_attribute": "server_side_encryption_configuration.0.kms_key_id" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "kendra_sse_kms_key_id_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0031_aws_memorydb_cluster_kms_key_arn.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0031_aws_memorydb_cluster_kms_key_arn.json new file mode 100644 index 00000000..62d80084 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0031_aws_memorydb_cluster_kms_key_arn.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0031", + "name": "Ensure MemoryDB is encrypted at rest using KMS CMKs", + "description": "Ensure MemoryDB is encrypted at rest using KMS CMKs", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + "evaluators": [ + { + "id": "kms_key_arn_set", + "description": "Every aws_memorydb_cluster sets a non-empty kms_key_arn; a null or absent kms_key_arn fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_memorydb_cluster", + "terraform_resource_attribute": "kms_key_arn" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "kms_key_arn_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0032_aws_lambda_permission_principal.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0032_aws_lambda_permission_principal.json new file mode 100644 index 00000000..36fc85c3 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0032_aws_lambda_permission_principal.json @@ -0,0 +1,32 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0032", + "name": "Ensure that AWS Lambda function is not publicly accessible", + "description": "Ensure that AWS Lambda function is not publicly accessible", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + "evaluators": [ + { + "id": "principal_not_wildcard", + "description": "No aws_lambda_permission grants invoke rights to the wildcard principal '*'. NotContainedIn with a list also passes on a null or absent principal.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_lambda_permission", + "terraform_resource_attribute": "principal" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "*" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "principal_not_wildcard" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0033_aws_lambda_function_runtime.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0033_aws_lambda_function_runtime.json new file mode 100644 index 00000000..2c77e3e3 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0033_aws_lambda_function_runtime.json @@ -0,0 +1,56 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0033", + "name": "Ensure Lambda Runtime is not deprecated", + "description": "Ensure Lambda Runtime is not deprecated", + "tags": [ + "cloud:aws", + "general_security" + ] + }, + "evaluators": [ + { + "id": "runtime_not_deprecated", + "description": "aws_lambda_function.runtime must not be one of the deprecated runtimes. A list-valued NotContainedIn also passes on a null runtime, which is what container-image packaged functions record.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_lambda_function", + "terraform_resource_attribute": "runtime" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "dotnetcore3.1", + "nodejs12.x", + "python3.6", + "python2.7", + "dotnet5.0", + "dotnetcore2.1", + "ruby2.5", + "nodejs10.x", + "nodejs8.10", + "nodejs4.3", + "nodejs6.10", + "dotnetcore1.0", + "dotnetcore2.0", + "nodejs4.3-edge", + "nodejs", + "java8", + "python3.7", + "go1.x", + "provided", + "ruby2.7", + "nodejs14.x", + "nodejs16.x", + "python3.9", + "dotnet7", + "dotnet6" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "runtime_not_deprecated" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0034_aws_mwaa_environment_logging_configuration_worker_logs_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0034_aws_mwaa_environment_logging_configuration_worker_logs_enabled.json new file mode 100644 index 00000000..7449507b --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0034_aws_mwaa_environment_logging_configuration_worker_logs_enabled.json @@ -0,0 +1,31 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0034", + "name": "Ensure MWAA environment has worker logs enabled", + "description": "Ensure MWAA environment has worker logs enabled", + "tags": [ + "cloud:aws", + "logging" + ], + "remediation": "In every aws_mwaa_environment logging_configuration block set worker_logs { enabled = true }." + }, + "evaluators": [ + { + "id": "worker_logs_enabled", + "description": "logging_configuration.worker_logs.enabled must be true on every aws_mwaa_environment; a missing block fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_mwaa_environment", + "terraform_resource_attribute": "logging_configuration.*.worker_logs.*.enabled" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "worker_logs_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0035_aws_neptune_cluster_backup_retention_period.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0035_aws_neptune_cluster_backup_retention_period.json new file mode 100644 index 00000000..81ba89e7 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0035_aws_neptune_cluster_backup_retention_period.json @@ -0,0 +1,31 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0035", + "name": "Ensure that Neptune DB cluster has automated backups enabled with adequate retention", + "description": "Ensure that Neptune DB cluster has automated backups enabled with adequate retention", + "tags": [ + "cloud:aws", + "backup_and_recovery" + ], + "remediation": "Set backup_retention_period to 7 or more on every aws_neptune_cluster." + }, + "evaluators": [ + { + "id": "backup_retention_at_least_7_days", + "description": "Every aws_neptune_cluster keeps backup_retention_period >= 7. The provider default is 1, so a cluster that omits the argument fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_neptune_cluster", + "terraform_resource_attribute": "backup_retention_period" + }, + "condition": { + "type": "GreaterThanEqualTo", + "value": 7, + "error_tolerance": 1 + } + } + ], + "eval_expression": "backup_retention_at_least_7_days" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0036_aws_redshift_cluster_publicly_accessible.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0036_aws_redshift_cluster_publicly_accessible.json new file mode 100644 index 00000000..4f0a454e --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0036_aws_redshift_cluster_publicly_accessible.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0036", + "name": "Redshift cluster should not be publicly accessible", + "description": "Redshift cluster should not be publicly accessible", + "tags": [ + "cloud:aws", + "networking" + ] + }, + "evaluators": [ + { + "id": "publicly_accessible_false", + "description": "Every aws_redshift_cluster sets publicly_accessible = false; a true, null or absent value fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_redshift_cluster", + "terraform_resource_attribute": "publicly_accessible" + }, + "condition": { + "type": "Equals", + "value": false, + "error_tolerance": 1 + } + } + ], + "eval_expression": "publicly_accessible_false" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0037_aws_s3_bucket_object_lock_configuration_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0037_aws_s3_bucket_object_lock_configuration_enabled.json new file mode 100644 index 00000000..bc80a065 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0037_aws_s3_bucket_object_lock_configuration_enabled.json @@ -0,0 +1,31 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0037", + "name": "Ensure that S3 bucket has lock configuration enabled by default", + "description": "Ensure that S3 bucket has lock configuration enabled by default", + "tags": [ + "cloud:aws", + "general_security" + ], + "remediation": "Set object_lock_configuration { object_lock_enabled = \"Enabled\" } on the aws_s3_bucket." + }, + "evaluators": [ + { + "id": "object_lock_enabled", + "description": "object_lock_configuration.0.object_lock_enabled must be \"Enabled\". A block present without the key contributes null and fails, while a bucket with no object_lock_configuration at all is tolerated away rather than failed.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_s3_bucket", + "terraform_resource_attribute": "object_lock_configuration.*.object_lock_enabled" + }, + "condition": { + "type": "Equals", + "value": "Enabled", + "error_tolerance": 2 + } + } + ], + "eval_expression": "object_lock_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0038_aws_s3_object_copy_kms_key_id.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0038_aws_s3_object_copy_kms_key_id.json new file mode 100644 index 00000000..4cdccca5 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0038_aws_s3_object_copy_kms_key_id.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0038", + "name": "Ensure S3 Object Copy is encrypted by KMS using a customer managed Key (CMK)", + "description": "Ensure S3 Object Copy is encrypted by KMS using a customer managed Key (CMK)", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Set kms_key_id to a customer managed KMS key on every aws_s3_object_copy." + }, + "evaluators": [ + { + "id": "kms_key_id_set", + "description": "kms_key_id must be a non-empty string. IsNotEmpty fails on null, and an unresolvable attribute is a severity-2 miss that also fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_s3_object_copy", + "terraform_resource_attribute": "kms_key_id" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "kms_key_id_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0039_aws_s3_bucket_object_kms_key_id.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0039_aws_s3_bucket_object_kms_key_id.json new file mode 100644 index 00000000..2380a9c8 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0039_aws_s3_bucket_object_kms_key_id.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0039", + "name": "Ensure S3 bucket Object is encrypted by KMS using a customer managed Key (CMK)", + "description": "Ensure S3 bucket Object is encrypted by KMS using a customer managed Key (CMK)", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Set kms_key_id to a customer managed KMS key on every aws_s3_bucket_object." + }, + "evaluators": [ + { + "id": "kms_key_id_set", + "description": "kms_key_id must be a non-empty string. IsNotEmpty fails on null, and an unresolvable attribute is a severity-2 miss that also fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_s3_bucket_object", + "terraform_resource_attribute": "kms_key_id" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "kms_key_id_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0040_aws_sagemaker_notebook_instance_root_access.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0040_aws_sagemaker_notebook_instance_root_access.json new file mode 100644 index 00000000..92ad9cb9 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0040_aws_sagemaker_notebook_instance_root_access.json @@ -0,0 +1,31 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0040", + "name": "Ensure SageMaker Users should not have root access to SageMaker notebook instances", + "description": "Ensure SageMaker Users should not have root access to SageMaker notebook instances", + "tags": [ + "cloud:aws", + "general_security" + ], + "remediation": "Set root_access = \"Disabled\" on every aws_sagemaker_notebook_instance." + }, + "evaluators": [ + { + "id": "root_access_disabled", + "description": "root_access must equal 'Disabled'. The provider default is 'Enabled', so a notebook that omits the argument shows 'Enabled' in the plan and fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_sagemaker_notebook_instance", + "terraform_resource_attribute": "root_access" + }, + "condition": { + "type": "Equals", + "value": "Disabled", + "error_tolerance": 1 + } + } + ], + "eval_expression": "root_access_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0041_aws_sagemaker_data_quality_job_definition_output_config_kms_key_id.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0041_aws_sagemaker_data_quality_job_definition_output_config_kms_key_id.json new file mode 100644 index 00000000..9bb61028 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0041_aws_sagemaker_data_quality_job_definition_output_config_kms_key_id.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0041", + "name": "Ensure Amazon Sagemaker Data Quality Job uses KMS to encrypt model artifacts", + "description": "Ensure Amazon Sagemaker Data Quality Job uses KMS to encrypt model artifacts", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Set data_quality_job_output_config.kms_key_id on every aws_sagemaker_data_quality_job_definition." + }, + "evaluators": [ + { + "id": "output_config_kms_key_id_set", + "description": "data_quality_job_output_config.0.kms_key_id must be a non-empty string. A null value, or an absent output config block, fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_sagemaker_data_quality_job_definition", + "terraform_resource_attribute": "data_quality_job_output_config.0.kms_key_id" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "output_config_kms_key_id_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0042_aws_sagemaker_notebook_instance_metadata_service_configuration_minimum.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0042_aws_sagemaker_notebook_instance_metadata_service_configuration_minimum.json new file mode 100644 index 00000000..20ca2a14 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0042_aws_sagemaker_notebook_instance_metadata_service_configuration_minimum.json @@ -0,0 +1,31 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0042", + "name": "Ensure Amazon SageMaker Notebook Instance only allows for IMDSv2", + "description": "Ensure Amazon SageMaker Notebook Instance only allows for IMDSv2", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Set instance_metadata_service_configuration { minimum_instance_metadata_service_version = \"2\" } on every aws_sagemaker_notebook_instance." + }, + "evaluators": [ + { + "id": "imdsv2_minimum_version", + "description": "instance_metadata_service_configuration.0.minimum_instance_metadata_service_version must be the string \"2\". An absent block makes the path unresolvable (severity 2) and fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_sagemaker_notebook_instance", + "terraform_resource_attribute": "instance_metadata_service_configuration.0.minimum_instance_metadata_service_version" + }, + "condition": { + "type": "Equals", + "value": "2", + "error_tolerance": 1 + } + } + ], + "eval_expression": "imdsv2_minimum_version" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0043_aws_sns_topic_kms_master_key_id.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0043_aws_sns_topic_kms_master_key_id.json new file mode 100644 index 00000000..4521c3b5 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0043_aws_sns_topic_kms_master_key_id.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0043", + "name": "Ensure all data stored in the SNS topic is encrypted", + "description": "Ensure all data stored in the SNS topic is encrypted", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Set kms_master_key_id on every aws_sns_topic." + }, + "evaluators": [ + { + "id": "sns_topic_kms_master_key", + "description": "kms_master_key_id must be a non-empty string on every aws_sns_topic. The attribute is optional, so an unset key arrives as an explicit null in change.after and fails IsNotEmpty.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_sns_topic", + "terraform_resource_attribute": "kms_master_key_id" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "sns_topic_kms_master_key" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0044_aws_ses_configuration_set_delivery_options_tls_policy.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0044_aws_ses_configuration_set_delivery_options_tls_policy.json new file mode 100644 index 00000000..46f7b90d --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0044_aws_ses_configuration_set_delivery_options_tls_policy.json @@ -0,0 +1,31 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0044", + "name": "Ensure SES Configuration Set enforces TLS usage", + "description": "Ensure SES Configuration Set enforces TLS usage", + "tags": [ + "cloud:aws", + "networking" + ], + "remediation": "Set delivery_options { tls_policy = \"Require\" } on every aws_ses_configuration_set." + }, + "evaluators": [ + { + "id": "ses_tls_policy_require", + "description": "The single delivery_options block of aws_ses_configuration_set must carry tls_policy = 'Require'. delivery_options is a list in the plan, hence the indexed path delivery_options.0.tls_policy; an absent or empty block is a severity-2 miss and fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_ses_configuration_set", + "terraform_resource_attribute": "delivery_options.0.tls_policy" + }, + "condition": { + "type": "Equals", + "value": "Require", + "error_tolerance": 1 + } + } + ], + "eval_expression": "ses_tls_policy_require" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0045_aws_sagemaker_endpoint_configuration_kms_key_arn.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0045_aws_sagemaker_endpoint_configuration_kms_key_arn.json new file mode 100644 index 00000000..fc83987a --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0045_aws_sagemaker_endpoint_configuration_kms_key_arn.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0045", + "name": "Ensure all data stored in the Sagemaker Endpoint is securely encrypted at rest", + "description": "Ensure all data stored in the Sagemaker Endpoint is securely encrypted at rest", + "tags": [ + "cloud:aws", + "encryption" + ], + "remediation": "Set kms_key_arn on every aws_sagemaker_endpoint_configuration." + }, + "evaluators": [ + { + "id": "endpoint_config_kms_key_arn", + "description": "kms_key_arn must be a non-empty string on every aws_sagemaker_endpoint_configuration. The attribute is optional, so an unset key arrives as an explicit null in change.after and fails IsNotEmpty.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_sagemaker_endpoint_configuration", + "terraform_resource_attribute": "kms_key_arn" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "endpoint_config_kms_key_arn" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0046_aws_workspaces_workspace_root_volume_encryption_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0046_aws_workspaces_workspace_root_volume_encryption_enabled.json new file mode 100644 index 00000000..78d8059c --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0046_aws_workspaces_workspace_root_volume_encryption_enabled.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0046", + "name": "Ensure that Workspace root volumes are encrypted", + "description": "Ensure that Workspace root volumes are encrypted", + "tags": [ + "cloud:aws", + "encryption" + ] + }, + "evaluators": [ + { + "id": "root_volume_encryption_enabled", + "description": "aws_workspaces_workspace must set root_volume_encryption_enabled = true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "aws_workspaces_workspace", + "terraform_resource_attribute": "root_volume_encryption_enabled" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "root_volume_encryption_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0047_azurerm_automation_account_public_network_access_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0047_azurerm_automation_account_public_network_access_enabled.json new file mode 100644 index 00000000..b5c1bfa9 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0047_azurerm_automation_account_public_network_access_enabled.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0047", + "name": "Ensure Azure automation account does NOT have overly permissive network access", + "description": "Ensure Azure automation account does NOT have overly permissive network access", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + "evaluators": [ + { + "id": "public_network_access_disabled", + "description": "public_network_access_enabled must be explicitly false", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_automation_account", + "terraform_resource_attribute": "public_network_access_enabled" + }, + "condition": { + "type": "Equals", + "value": false, + "error_tolerance": 1 + } + } + ], + "eval_expression": "public_network_access_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0048_azurerm_automation_account_identity_type.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0048_azurerm_automation_account_identity_type.json new file mode 100644 index 00000000..d0372022 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0048_azurerm_automation_account_identity_type.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0048", + "name": "Ensure Azure automation account is configured with managed identity", + "description": "Ensure Azure automation account is configured with managed identity", + "tags": [ + "cloud:azure", + "iam" + ] + }, + "evaluators": [ + { + "id": "identity_type_set", + "description": "an identity block with a non-empty type must be present", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_automation_account", + "terraform_resource_attribute": "identity.*.type" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "identity_type_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0049_azurerm_api_management_security_enable_backend_ssl30.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0049_azurerm_api_management_security_enable_backend_ssl30.json new file mode 100644 index 00000000..2177d820 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0049_azurerm_api_management_security_enable_backend_ssl30.json @@ -0,0 +1,86 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0049", + "name": "Ensure API management uses at least TLS 1.2", + "description": "Ensure API management uses at least TLS 1.2", + "tags": [ + "cloud:azure", + "encryption" + ] + }, + "evaluators": [ + { + "id": "backend_ssl30_disabled", + "description": "azurerm_api_management.security.0.enable_backend_ssl30 must not be true. NotEquals passes on an explicit null, i.e. a security block that does not carry the key; error_tolerance 2 skips the resource when the whole security block is absent from change.after.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_api_management", + "terraform_resource_attribute": "security.0.enable_backend_ssl30" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 2 + } + }, + { + "id": "backend_tls10_disabled", + "description": "azurerm_api_management.security.0.enable_backend_tls10 must not be true. NotEquals passes on an explicit null, i.e. a security block that does not carry the key; error_tolerance 2 skips the resource when the whole security block is absent from change.after.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_api_management", + "terraform_resource_attribute": "security.0.enable_backend_tls10" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 2 + } + }, + { + "id": "frontend_ssl30_disabled", + "description": "azurerm_api_management.security.0.enable_frontend_ssl30 must not be true. NotEquals passes on an explicit null, i.e. a security block that does not carry the key; error_tolerance 2 skips the resource when the whole security block is absent from change.after.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_api_management", + "terraform_resource_attribute": "security.0.enable_frontend_ssl30" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 2 + } + }, + { + "id": "frontend_tls10_disabled", + "description": "azurerm_api_management.security.0.enable_frontend_tls10 must not be true. NotEquals passes on an explicit null, i.e. a security block that does not carry the key; error_tolerance 2 skips the resource when the whole security block is absent from change.after.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_api_management", + "terraform_resource_attribute": "security.0.enable_frontend_tls10" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 2 + } + }, + { + "id": "frontend_tls11_disabled", + "description": "azurerm_api_management.security.0.enable_frontend_tls11 must not be true. NotEquals passes on an explicit null, i.e. a security block that does not carry the key; error_tolerance 2 skips the resource when the whole security block is absent from change.after.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_api_management", + "terraform_resource_attribute": "security.0.enable_frontend_tls11" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 2 + } + } + ], + "eval_expression": "backend_ssl30_disabled && backend_tls10_disabled && frontend_ssl30_disabled && frontend_tls10_disabled && frontend_tls11_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0050_azurerm_app_service_site_config_cors_allowed_origins.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0050_azurerm_app_service_site_config_cors_allowed_origins.json new file mode 100644 index 00000000..c12c4db6 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0050_azurerm_app_service_site_config_cors_allowed_origins.json @@ -0,0 +1,64 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0050", + "name": "Ensure that CORS disallows every resource to access app services", + "description": "Ensure that CORS disallows every resource to access app services", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + "evaluators": [ + { + "id": "app_service_cors_not_wildcard", + "description": "azurerm_app_service site_config.cors.allowed_origins is not exactly [\"*\"]", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_app_service", + "terraform_resource_attribute": "site_config.*.cors.*.allowed_origins" + }, + "condition": { + "type": "NotEquals", + "value": [ + "*" + ], + "error_tolerance": 1 + } + }, + { + "id": "linux_web_app_cors_not_wildcard", + "description": "azurerm_linux_web_app site_config.cors.allowed_origins is not exactly [\"*\"]", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_linux_web_app", + "terraform_resource_attribute": "site_config.*.cors.*.allowed_origins" + }, + "condition": { + "type": "NotEquals", + "value": [ + "*" + ], + "error_tolerance": 1 + } + }, + { + "id": "windows_web_app_cors_not_wildcard", + "description": "azurerm_windows_web_app site_config.cors.allowed_origins is not exactly [\"*\"]", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_windows_web_app", + "terraform_resource_attribute": "site_config.*.cors.*.allowed_origins" + }, + "condition": { + "type": "NotEquals", + "value": [ + "*" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "app_service_cors_not_wildcard && linux_web_app_cors_not_wildcard && windows_web_app_cors_not_wildcard" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0051_azurerm_app_service_storage_account_type.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0051_azurerm_app_service_storage_account_type.json new file mode 100644 index 00000000..fffaa774 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0051_azurerm_app_service_storage_account_type.json @@ -0,0 +1,58 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0051", + "name": "Ensure that app services use Azure Files", + "description": "Ensure that app services use Azure Files", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + "evaluators": [ + { + "id": "app_service_storage_account_type", + "description": "azurerm_app_service storage_account.type is AzureFiles", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_app_service", + "terraform_resource_attribute": "storage_account.0.type" + }, + "condition": { + "type": "Equals", + "value": "AzureFiles", + "error_tolerance": 1 + } + }, + { + "id": "linux_web_app_storage_account_type", + "description": "azurerm_linux_web_app storage_account.type is AzureFiles", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_linux_web_app", + "terraform_resource_attribute": "storage_account.0.type" + }, + "condition": { + "type": "Equals", + "value": "AzureFiles", + "error_tolerance": 1 + } + }, + { + "id": "windows_web_app_storage_account_type", + "description": "azurerm_windows_web_app storage_account.type is AzureFiles", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_windows_web_app", + "terraform_resource_attribute": "storage_account.0.type" + }, + "condition": { + "type": "Equals", + "value": "AzureFiles", + "error_tolerance": 1 + } + } + ], + "eval_expression": "app_service_storage_account_type && linux_web_app_storage_account_type && windows_web_app_storage_account_type" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0052_azurerm_container_registry_sku.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0052_azurerm_container_registry_sku.json new file mode 100644 index 00000000..fb6dd84b --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0052_azurerm_container_registry_sku.json @@ -0,0 +1,43 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0052", + "name": "Ensure geo-replicated container registries to match multi-region container deployments.", + "description": "Ensure geo-replicated container registries to match multi-region container deployments.", + "tags": [ + "cloud:azure", + "networking" + ] + }, + "evaluators": [ + { + "id": "sku_is_premium", + "description": "azurerm_container_registry.sku must be 'Premium' — geo-replication is a Premium-only feature, so both halves of this policy have to hold.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_container_registry", + "terraform_resource_attribute": "sku" + }, + "condition": { + "type": "Equals", + "value": "Premium", + "error_tolerance": 1 + } + }, + { + "id": "georeplications_present", + "description": "azurerm_container_registry.georeplications must be a non-empty list. An empty list, or an unresolvable attribute (severity 2 > tolerance 1), both fail.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_container_registry", + "terraform_resource_attribute": "georeplications" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "sku_is_premium && georeplications_present" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0053_azurerm_container_registry_quarantine_policy_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0053_azurerm_container_registry_quarantine_policy_enabled.json new file mode 100644 index 00000000..1fb78048 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0053_azurerm_container_registry_quarantine_policy_enabled.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0053", + "name": "Ensure container image quarantine, scan, and mark images verified", + "description": "Ensure container image quarantine, scan, and mark images verified", + "tags": [ + "cloud:azure", + "supply_chain" + ] + }, + "evaluators": [ + { + "id": "quarantine_policy_enabled", + "description": "azurerm_container_registry.quarantine_policy_enabled must be true. The provider default is false, and an unresolvable attribute fails at tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_container_registry", + "terraform_resource_attribute": "quarantine_policy_enabled" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "quarantine_policy_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0054_azurerm_data_factory_public_network_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0054_azurerm_data_factory_public_network_enabled.json new file mode 100644 index 00000000..dcd17e25 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0054_azurerm_data_factory_public_network_enabled.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0054", + "name": "Ensure that Azure Data factory public network access is disabled", + "description": "Ensure that Azure Data factory public network access is disabled", + "tags": [ + "cloud:azure", + "networking" + ] + }, + "evaluators": [ + { + "id": "public_network_disabled", + "description": "azurerm_data_factory.public_network_enabled must be false. The provider default of true appears in change.after and fails; an unresolvable attribute is a severity-2 miss that also fails at tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_data_factory", + "terraform_resource_attribute": "public_network_enabled" + }, + "condition": { + "type": "Equals", + "value": false, + "error_tolerance": 1 + } + } + ], + "eval_expression": "public_network_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0055_azurerm_container_group_subnet_ids.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0055_azurerm_container_group_subnet_ids.json new file mode 100644 index 00000000..1f0de7f5 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0055_azurerm_container_group_subnet_ids.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0055", + "name": "Ensure that Azure Container group is deployed into virtual network", + "description": "Ensure that Azure Container group is deployed into virtual network", + "tags": [ + "cloud:azure", + "networking" + ] + }, + "evaluators": [ + { + "id": "subnet_ids_set", + "description": "azurerm_container_group.subnet_ids must be a non-empty list. IsNotEmpty fails on null and on an empty list, and an unresolvable attribute is a severity-2 miss that fails at tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_container_group", + "terraform_resource_attribute": "subnet_ids" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "subnet_ids_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0056_azurerm_frontdoor_frontend_endpoint_web_application_firewall_policy_li.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0056_azurerm_frontdoor_frontend_endpoint_web_application_firewall_policy_li.json new file mode 100644 index 00000000..d4219963 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0056_azurerm_frontdoor_frontend_endpoint_web_application_firewall_policy_li.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0056", + "name": "Ensure that Azure Front Door enables WAF", + "description": "Ensure that Azure Front Door enables WAF", + "tags": [ + "cloud:azure", + "networking" + ] + }, + "evaluators": [ + { + "id": "frontdoor_endpoint_waf_policy_linked", + "description": "The first frontend endpoint of an azurerm_frontdoor must link a WAF policy: frontend_endpoint.0.web_application_firewall_policy_link_id must be non-empty. The segment is indexed, not wildcarded, so only the first endpoint is read. A front door whose first endpoint links no policy is a severity-2 attribute miss and fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_frontdoor", + "terraform_resource_attribute": "frontend_endpoint.0.web_application_firewall_policy_link_id" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "frontdoor_endpoint_waf_policy_linked" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0057_azurerm_eventgrid_topic_identity_type.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0057_azurerm_eventgrid_topic_identity_type.json new file mode 100644 index 00000000..b9ba54a9 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0057_azurerm_eventgrid_topic_identity_type.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0057", + "name": "Ensure that Managed identity provider is enabled for Azure Event Grid Topic", + "description": "Ensure that Managed identity provider is enabled for Azure Event Grid Topic", + "tags": [ + "cloud:azure", + "iam" + ] + }, + "evaluators": [ + { + "id": "eventgrid_topic_identity_type_set", + "description": "Every azurerm_eventgrid_topic must declare a managed identity. The identity block is a single-element list in change.after, so the path is identity.0.type and the requirement is a non-empty string; a topic with no identity block yields a severity-2 attribute miss and fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_eventgrid_topic", + "terraform_resource_attribute": "identity.0.type" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "eventgrid_topic_identity_type_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0058_azurerm_eventhub_namespace_location.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0058_azurerm_eventhub_namespace_location.json new file mode 100644 index 00000000..0ab7155f --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0058_azurerm_eventhub_namespace_location.json @@ -0,0 +1,101 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0058", + "name": "Ensure the Azure Event Hub Namespace is zone redundant", + "description": "Ensure the Azure Event Hub Namespace is zone redundant", + "tags": [ + "cloud:azure", + "backup_and_recovery" + ] + }, + "evaluators": [ + { + "id": "eventhub_namespace_in_zone_redundant_region", + "description": "Zone redundancy for Event Hub namespaces is decided by the region, so the location attribute is tested for membership of the zone-redundant list. The list carries both the display form ('West Europe') and the normalised slug ('westeurope'), so it matches whichever spelling the plan records. A namespace with no location in change.after is a severity-2 miss and fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_eventhub_namespace", + "terraform_resource_attribute": "location" + }, + "condition": { + "type": "ContainedIn", + "value": [ + "Australia East", + "australiaeast", + "Central India", + "centralindia", + "China North 3", + "chinanorth3", + "East Asia", + "eastasia", + "Indonesia Central", + "indonesiacentral", + "Japan East", + "japaneast", + "Japan West", + "japanwest", + "Korea Central", + "koreacentral", + "New Zealand North", + "newzealandnorth", + "South Africa North", + "southafricanorth", + "Southeast Asia", + "southeastasia", + "Canada Central", + "canadacentral", + "France Central", + "francecentral", + "Germany West Central", + "germanywestcentral", + "Italy North", + "italynorth", + "North Europe", + "northeurope", + "Norway East", + "norwayeast", + "Poland Central", + "polandcentral", + "Spain Central", + "spaincentral", + "Sweden Central", + "swedencentral", + "Switzerland North", + "switzerlandnorth", + "UK South", + "uksouth", + "West Europe", + "westeurope", + "Mexico Central", + "mexicocentral", + "Israel Central", + "israelcentral", + "Qatar Central", + "qatarcentral", + "UAE North", + "uaenorth", + "Brazil South", + "brazilsouth", + "Central US", + "centralus", + "East US", + "eastus", + "East US 2", + "eastus2", + "South Central US", + "southcentralus", + "US Gov Virginia", + "usgovvirginia", + "West US 2", + "westus2", + "West US 3", + "westus3" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "eventhub_namespace_in_zone_redundant_region" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0059_azurerm_iothub_public_network_access_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0059_azurerm_iothub_public_network_access_enabled.json new file mode 100644 index 00000000..4a6290b8 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0059_azurerm_iothub_public_network_access_enabled.json @@ -0,0 +1,32 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0059", + "name": "Ensure that Azure IoT Hub disables public network access", + "description": "Ensure that Azure IoT Hub disables public network access", + "tags": [ + "cloud:azure", + "networking" + ] + }, + "evaluators": [ + { + "id": "iothub_public_network_access_not_enabled", + "description": "No azurerm_iothub has public_network_access_enabled = true; a null value passes.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_iothub", + "terraform_resource_attribute": "public_network_access_enabled" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + true + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "iothub_public_network_access_not_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0060_azurerm_kubernetes_cluster_default_node_pool_max_pods.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0060_azurerm_kubernetes_cluster_default_node_pool_max_pods.json new file mode 100644 index 00000000..17a5fef0 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0060_azurerm_kubernetes_cluster_default_node_pool_max_pods.json @@ -0,0 +1,44 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0060", + "name": "Ensure Azure Kubernetes Cluster (AKS) nodes should use a minimum number of 50 pods.", + "description": "Ensure Azure Kubernetes Cluster (AKS) nodes should use a minimum number of 50 pods.", + "tags": [ + "cloud:azure", + "kubernetes" + ] + }, + "evaluators": [ + { + "id": "cluster_default_node_pool_max_pods", + "description": "default_node_pool.max_pods must be at least 50. An unset value is null and never satisfies a numeric comparison, which is the right verdict: the effective default is 30.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_kubernetes_cluster", + "terraform_resource_attribute": "default_node_pool.*.max_pods" + }, + "condition": { + "type": "GreaterThanEqualTo", + "value": 50, + "error_tolerance": 1 + } + }, + { + "id": "node_pool_max_pods", + "description": "Standalone node pools must set max_pods >= 50", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_kubernetes_cluster_node_pool", + "terraform_resource_attribute": "max_pods" + }, + "condition": { + "type": "GreaterThanEqualTo", + "value": 50, + "error_tolerance": 1 + } + } + ], + "eval_expression": "cluster_default_node_pool_max_pods && node_pool_max_pods" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0061_azurerm_kusto_cluster_identity_type.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0061_azurerm_kusto_cluster_identity_type.json new file mode 100644 index 00000000..e95e85cc --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0061_azurerm_kusto_cluster_identity_type.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0061", + "name": "Ensure that data explorer/Kusto uses managed identities to access Azure resources securely.", + "description": "Ensure that data explorer/Kusto uses managed identities to access Azure resources securely.", + "tags": [ + "cloud:azure", + "iam" + ] + }, + "evaluators": [ + { + "id": "kusto_identity_type_set", + "description": "azurerm_kusto_cluster must declare an identity block with a non-empty type; an absent identity block is a severity-2 miss that fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_kusto_cluster", + "terraform_resource_attribute": "identity.*.type" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "kusto_identity_type_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0062_azurerm_monitor_log_profile_categories.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0062_azurerm_monitor_log_profile_categories.json new file mode 100644 index 00000000..4e0ffa59 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0062_azurerm_monitor_log_profile_categories.json @@ -0,0 +1,58 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0062", + "name": "Ensure audit profile captures all the activities", + "description": "Ensure audit profile captures all the activities", + "tags": [ + "cloud:azure", + "logging" + ] + }, + "evaluators": [ + { + "id": "captures_write", + "description": "azurerm_monitor_log_profile categories contains Write", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_monitor_log_profile", + "terraform_resource_attribute": "categories" + }, + "condition": { + "type": "Contains", + "value": "Write", + "error_tolerance": 1 + } + }, + { + "id": "captures_delete", + "description": "azurerm_monitor_log_profile categories contains Delete", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_monitor_log_profile", + "terraform_resource_attribute": "categories" + }, + "condition": { + "type": "Contains", + "value": "Delete", + "error_tolerance": 1 + } + }, + { + "id": "captures_action", + "description": "azurerm_monitor_log_profile categories contains Action", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_monitor_log_profile", + "terraform_resource_attribute": "categories" + }, + "condition": { + "type": "Contains", + "value": "Action", + "error_tolerance": 1 + } + } + ], + "eval_expression": "captures_write && captures_delete && captures_action" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0063_azurerm_network_interface_enable_ip_forwarding.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0063_azurerm_network_interface_enable_ip_forwarding.json new file mode 100644 index 00000000..81088365 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0063_azurerm_network_interface_enable_ip_forwarding.json @@ -0,0 +1,32 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0063", + "name": "Ensure that Network Interfaces disable IP forwarding", + "description": "Ensure that Network Interfaces disable IP forwarding", + "tags": [ + "cloud:azure", + "networking" + ] + }, + "evaluators": [ + { + "id": "nic_ip_forwarding_disabled", + "description": "azurerm_network_interface.enable_ip_forwarding must not be true (unset is acceptable)", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_network_interface", + "terraform_resource_attribute": "enable_ip_forwarding" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + true + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "nic_ip_forwarding_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0064_azurerm_search_service_public_network_access_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0064_azurerm_search_service_public_network_access_enabled.json new file mode 100644 index 00000000..9fdd045c --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0064_azurerm_search_service_public_network_access_enabled.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0064", + "name": "Ensure that Azure Cognitive Search disables public network access", + "description": "Ensure that Azure Cognitive Search disables public network access", + "tags": [ + "cloud:azure", + "networking" + ] + }, + "evaluators": [ + { + "id": "search_public_network_access_disabled", + "description": "azurerm_search_service.public_network_access_enabled must be false", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_search_service", + "terraform_resource_attribute": "public_network_access_enabled" + }, + "condition": { + "type": "Equals", + "value": false, + "error_tolerance": 1 + } + } + ], + "eval_expression": "search_public_network_access_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0065_azurerm_search_service_replica_count.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0065_azurerm_search_service_replica_count.json new file mode 100644 index 00000000..c09e7a20 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0065_azurerm_search_service_replica_count.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0065", + "name": "Ensure that Azure Cognitive Search maintains SLA for search index queries", + "description": "Ensure that Azure Cognitive Search maintains SLA for search index queries", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + "evaluators": [ + { + "id": "search_replica_count_at_least_two", + "description": "azurerm_search_service.replica_count must be at least 2 to receive the index query SLA", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_search_service", + "terraform_resource_attribute": "replica_count" + }, + "condition": { + "type": "GreaterThanEqualTo", + "value": 2, + "error_tolerance": 1 + } + } + ], + "eval_expression": "search_replica_count_at_least_two" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0066_azurerm_service_fabric_cluster_azure_active_directory_tenant_id.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0066_azurerm_service_fabric_cluster_azure_active_directory_tenant_id.json new file mode 100644 index 00000000..c8573bf3 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0066_azurerm_service_fabric_cluster_azure_active_directory_tenant_id.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0066", + "name": "Ensures that Active Directory is used for authentication for Service Fabric", + "description": "Ensures that Active Directory is used for authentication for Service Fabric", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + "evaluators": [ + { + "id": "aad_tenant_id_is_set", + "description": "Every azurerm_service_fabric_cluster must declare an azure_active_directory block with a non-empty tenant_id", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_service_fabric_cluster", + "terraform_resource_attribute": "azure_active_directory.0.tenant_id" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "aad_tenant_id_is_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0067_azurerm_service_plan_worker_count.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0067_azurerm_service_plan_worker_count.json new file mode 100644 index 00000000..dd6f2baf --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0067_azurerm_service_plan_worker_count.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0067", + "name": "Ensure App Service has a minimum number of instances for failover", + "description": "Ensure App Service has a minimum number of instances for failover", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + "evaluators": [ + { + "id": "worker_count_above_one", + "description": "Every azurerm_service_plan must set worker_count greater than 1", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_service_plan", + "terraform_resource_attribute": "worker_count" + }, + "condition": { + "type": "GreaterThan", + "value": 1, + "error_tolerance": 1 + } + } + ], + "eval_expression": "worker_count_above_one" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0068_azurerm_service_plan_zone_balancing_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0068_azurerm_service_plan_zone_balancing_enabled.json new file mode 100644 index 00000000..cfa82c97 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0068_azurerm_service_plan_zone_balancing_enabled.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0068", + "name": "Ensure the App Service Plan is zone redundant", + "description": "Ensure the App Service Plan is zone redundant", + "tags": [ + "cloud:azure", + "backup_and_recovery" + ] + }, + "evaluators": [ + { + "id": "zone_balancing_enabled", + "description": "Every azurerm_service_plan must set zone_balancing_enabled = true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_service_plan", + "terraform_resource_attribute": "zone_balancing_enabled" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "zone_balancing_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0069_azurerm_security_center_contact_alerts_to_admins.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0069_azurerm_security_center_contact_alerts_to_admins.json new file mode 100644 index 00000000..b68abc27 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0069_azurerm_security_center_contact_alerts_to_admins.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0069", + "name": "Ensure that 'Send email notification for high severity alerts' is set to 'On'", + "description": "Ensure that 'Send email notification for high severity alerts' is set to 'On'", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + "evaluators": [ + { + "id": "alerts_to_admins_enabled", + "description": "Every azurerm_security_center_contact must set alerts_to_admins = true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_security_center_contact", + "terraform_resource_attribute": "alerts_to_admins" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "alerts_to_admins_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0070_azurerm_servicebus_namespace_customer_managed_key_infrastructure_encry.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0070_azurerm_servicebus_namespace_customer_managed_key_infrastructure_encry.json new file mode 100644 index 00000000..c1130a17 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0070_azurerm_servicebus_namespace_customer_managed_key_infrastructure_encry.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0070", + "name": "Ensure that Azure Service Bus uses double encryption", + "description": "Ensure that Azure Service Bus uses double encryption", + "tags": [ + "cloud:azure", + "encryption" + ] + }, + "evaluators": [ + { + "id": "infrastructure_encryption_enabled", + "description": "azurerm_servicebus_namespace customer_managed_key[0].infrastructure_encryption_enabled must be true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_servicebus_namespace", + "terraform_resource_attribute": "customer_managed_key.0.infrastructure_encryption_enabled" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "infrastructure_encryption_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0071_azurerm_virtual_machine_storage_os_disk_managed_type.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0071_azurerm_virtual_machine_storage_os_disk_managed_type.json new file mode 100644 index 00000000..32149007 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0071_azurerm_virtual_machine_storage_os_disk_managed_type.json @@ -0,0 +1,42 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0071", + "name": "Ensure Virtual Machines are utilizing Managed Disks", + "description": "Ensure Virtual Machines are utilizing Managed Disks", + "tags": [ + "cloud:azure", + "general_security" + ] + }, + "evaluators": [ + { + "id": "managed_disk_type_set", + "description": "storage_os_disk.managed_disk_type must be set. storage_os_disk is a MaxItems-1 block, so the plan path is storage_os_disk.0.managed_disk_type; IsNotEmpty demands a real non-empty string such as Premium_LRS. A null (unresolved or unset) value fails, and an absent storage_os_disk block is a severity-2 miss that also fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_virtual_machine", + "terraform_resource_attribute": "storage_os_disk.0.managed_disk_type" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + }, + { + "id": "no_unmanaged_vhd_uri", + "description": "The second half of the requirement: storage_os_disk.vhd_uri must not be set. In the plan the key is present with a null value when unmanaged storage is not used, and IsEmpty is true for null and the empty string, so this passes exactly when no blob URI was supplied and fails on a concrete https://...vhd URI.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_virtual_machine", + "terraform_resource_attribute": "storage_os_disk.0.vhd_uri" + }, + "condition": { + "type": "IsEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "managed_disk_type_set && no_unmanaged_vhd_uri" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0072_azurerm_web_application_firewall_policy_settings_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0072_azurerm_web_application_firewall_policy_settings_enabled.json new file mode 100644 index 00000000..40e1ef86 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0072_azurerm_web_application_firewall_policy_settings_enabled.json @@ -0,0 +1,32 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0072", + "name": "Ensure that Application Gateway uses WAF in \"Detection\" or \"Prevention\" modes", + "description": "Ensure that Application Gateway uses WAF in \"Detection\" or \"Prevention\" modes", + "tags": [ + "cloud:azure", + "networking" + ] + }, + "evaluators": [ + { + "id": "waf_policy_settings_enabled", + "description": "A policy_settings block, when present, must have enabled truthy. policy_settings is a MaxItems-1 block, so the plan path is policy_settings.0.enabled; the deny-list form fails on an explicit false while passing on true or null. error_tolerance is 2 because an omitted policy_settings block leaves the path unresolvable (a severity-2 miss over an empty list), which is not a violation.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "azurerm_web_application_firewall_policy", + "terraform_resource_attribute": "policy_settings.0.enabled" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + false + ], + "error_tolerance": 2 + } + } + ], + "eval_expression": "waf_policy_settings_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0073_digitalocean_firewall_inbound_rule_source_addresses.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0073_digitalocean_firewall_inbound_rule_source_addresses.json new file mode 100644 index 00000000..184072ef --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0073_digitalocean_firewall_inbound_rule_source_addresses.json @@ -0,0 +1,33 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0073", + "name": "Ensure the firewall ingress is not wide open", + "description": "Ensure the firewall ingress is not wide open", + "tags": [ + "cloud:digitalocean", + "networking" + ] + }, + "evaluators": [ + { + "id": "inbound_source_addresses_not_open", + "description": "Every source address of every inbound_rule of digitalocean_firewall must be neither 0.0.0.0/0 nor ::/0. The doubled wildcard flattens the addresses of all inbound rules into one value per address; a rule that uses source_tags or source_droplet_ids instead contributes a padded null, and NotContainedIn over a list passes on null, so such a rule is not flagged.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "digitalocean_firewall", + "terraform_resource_attribute": "inbound_rule.*.source_addresses.*" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "0.0.0.0/0", + "::/0" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "inbound_source_addresses_not_open" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0074_google_bigquery_table_deletion_protection.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0074_google_bigquery_table_deletion_protection.json new file mode 100644 index 00000000..8bb65a10 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0074_google_bigquery_table_deletion_protection.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0074", + "name": "Ensure BigQuery tables have deletion protection enabled", + "description": "Ensure BigQuery tables have deletion protection enabled", + "tags": [ + "cloud:gcp", + "general_security" + ] + }, + "evaluators": [ + { + "id": "deletion_protection_enabled", + "description": "google_bigquery_table must set deletion_protection to true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_bigquery_table", + "terraform_resource_attribute": "deletion_protection" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "deletion_protection_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0075_google_bigquery_table_encryption_configuration_kms_key_name.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0075_google_bigquery_table_encryption_configuration_kms_key_name.json new file mode 100644 index 00000000..d82fb04e --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0075_google_bigquery_table_encryption_configuration_kms_key_name.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0075", + "name": "Ensure Big Query Tables are encrypted with Customer Supplied Encryption Keys (CSEK)", + "description": "Ensure Big Query Tables are encrypted with Customer Supplied Encryption Keys (CSEK)", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + "evaluators": [ + { + "id": "encryption_configuration_kms_key_name_set", + "description": "google_bigquery_table must set encryption_configuration[0].kms_key_name", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_bigquery_table", + "terraform_resource_attribute": "encryption_configuration.0.kms_key_name" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "encryption_configuration_kms_key_name_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0076_google_artifact_registry_repository_kms_key_name.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0076_google_artifact_registry_repository_kms_key_name.json new file mode 100644 index 00000000..39ac2e3c --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0076_google_artifact_registry_repository_kms_key_name.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0076", + "name": "Ensure Artifact Registry Repositories are encrypted with Customer Supplied Encryption Keys (CSEK)", + "description": "Ensure Artifact Registry Repositories are encrypted with Customer Supplied Encryption Keys (CSEK)", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + "evaluators": [ + { + "id": "kms_key_name_set", + "description": "google_artifact_registry_repository must set kms_key_name to a non-empty value", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_artifact_registry_repository", + "terraform_resource_attribute": "kms_key_name" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "kms_key_name_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0077_google_compute_disk_encryption_key.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0077_google_compute_disk_encryption_key.json new file mode 100644 index 00000000..7d5f9278 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0077_google_compute_disk_encryption_key.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0077", + "name": "Ensure VM disks for critical VMs are encrypted with Customer Supplied Encryption Keys (CSEK)", + "description": "Ensure VM disks for critical VMs are encrypted with Customer Supplied Encryption Keys (CSEK)", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + "evaluators": [ + { + "id": "disk_encryption_key_present", + "description": "google_compute_disk must declare a disk_encryption_key block. Terraform renders an unconfigured block list as [], which IsNotEmpty rejects; a disk whose change.after has no disk_encryption_key key is a severity-2 miss and fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_compute_disk", + "terraform_resource_attribute": "disk_encryption_key" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "disk_encryption_key_present" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0078_google_compute_instance_shielded_config.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0078_google_compute_instance_shielded_config.json new file mode 100644 index 00000000..0ed31ecd --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0078_google_compute_instance_shielded_config.json @@ -0,0 +1,139 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0078", + "name": "Ensure Compute instances are launched with Shielded VM enabled", + "description": "Ensure Compute instances are launched with Shielded VM enabled", + "tags": [ + "cloud:gcp", + "general_security" + ] + }, + "evaluators": [ + { + "id": "instance_shielded_config_present", + "description": "google_compute_instance must declare a shielded_instance_config block; terraform renders an unconfigured block list as [], which IsNotEmpty rejects.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_compute_instance", + "terraform_resource_attribute": "shielded_instance_config" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + }, + { + "id": "instance_vtpm_not_disabled", + "description": "google_compute_instance shielded_instance_config.enable_vtpm must not be false. NotEquals passes on null, so a block that omits the key keeps the provider default and only an explicitly disabled vTPM fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_compute_instance", + "terraform_resource_attribute": "shielded_instance_config.*.enable_vtpm" + }, + "condition": { + "type": "NotEquals", + "value": false, + "error_tolerance": 1 + } + }, + { + "id": "instance_integrity_monitoring_not_disabled", + "description": "google_compute_instance shielded_instance_config.enable_integrity_monitoring must not be false.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_compute_instance", + "terraform_resource_attribute": "shielded_instance_config.*.enable_integrity_monitoring" + }, + "condition": { + "type": "NotEquals", + "value": false, + "error_tolerance": 1 + } + }, + { + "id": "instance_template_shielded_config_present", + "description": "Same block-presence check for google_compute_instance_template.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_compute_instance_template", + "terraform_resource_attribute": "shielded_instance_config" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + }, + { + "id": "instance_template_vtpm_not_disabled", + "description": "Same enable_vtpm check for google_compute_instance_template.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_compute_instance_template", + "terraform_resource_attribute": "shielded_instance_config.*.enable_vtpm" + }, + "condition": { + "type": "NotEquals", + "value": false, + "error_tolerance": 1 + } + }, + { + "id": "instance_template_integrity_monitoring_not_disabled", + "description": "Same enable_integrity_monitoring check for google_compute_instance_template.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_compute_instance_template", + "terraform_resource_attribute": "shielded_instance_config.*.enable_integrity_monitoring" + }, + "condition": { + "type": "NotEquals", + "value": false, + "error_tolerance": 1 + } + }, + { + "id": "instance_from_template_shielded_config_present", + "description": "Same block-presence check for google_compute_instance_from_template.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_compute_instance_from_template", + "terraform_resource_attribute": "shielded_instance_config" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + }, + { + "id": "instance_from_template_vtpm_not_disabled", + "description": "Same enable_vtpm check for google_compute_instance_from_template.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_compute_instance_from_template", + "terraform_resource_attribute": "shielded_instance_config.*.enable_vtpm" + }, + "condition": { + "type": "NotEquals", + "value": false, + "error_tolerance": 1 + } + }, + { + "id": "instance_from_template_integrity_monitoring_not_disabled", + "description": "Same enable_integrity_monitoring check for google_compute_instance_from_template.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_compute_instance_from_template", + "terraform_resource_attribute": "shielded_instance_config.*.enable_integrity_monitoring" + }, + "condition": { + "type": "NotEquals", + "value": false, + "error_tolerance": 1 + } + } + ], + "eval_expression": "instance_shielded_config_present && instance_vtpm_not_disabled && instance_integrity_monitoring_not_disabled && instance_template_shielded_config_present && instance_template_vtpm_not_disabled && instance_template_integrity_monitoring_not_disabled && instance_from_template_shielded_config_present && instance_from_template_vtpm_not_disabled && instance_from_template_integrity_monitoring_not_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0079_google_container_cluster_logging_service.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0079_google_container_cluster_logging_service.json new file mode 100644 index 00000000..ccc6c699 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0079_google_container_cluster_logging_service.json @@ -0,0 +1,32 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0079", + "name": "Ensure Stackdriver Logging is set to Enabled on Kubernetes Engine Clusters", + "description": "Ensure Stackdriver Logging is set to Enabled on Kubernetes Engine Clusters", + "tags": [ + "cloud:gcp", + "kubernetes" + ] + }, + "evaluators": [ + { + "id": "logging_service_not_none", + "description": "google_container_cluster.logging_service must not be 'none'", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_container_cluster", + "terraform_resource_attribute": "logging_service" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "none" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "logging_service_not_none" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0080_google_container_cluster_private_config.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0080_google_container_cluster_private_config.json new file mode 100644 index 00000000..43c9005f --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0080_google_container_cluster_private_config.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0080", + "name": "Ensure Kubernetes Cluster is created with Private cluster enabled", + "description": "Ensure Kubernetes Cluster is created with Private cluster enabled", + "tags": [ + "cloud:gcp", + "kubernetes" + ] + }, + "evaluators": [ + { + "id": "private_cluster_config_present", + "description": "google_container_cluster must declare a private_cluster_config block. In the plan the block is a list, so IsNotEmpty rejects both the empty list produced when the block is omitted and the null terraform writes when the computed block is unknown; an absent key is a severity-2 miss and also fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_container_cluster", + "terraform_resource_attribute": "private_cluster_config" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "private_cluster_config_present" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0081_google_document_ai_warehouse_location_kms_key.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0081_google_document_ai_warehouse_location_kms_key.json new file mode 100644 index 00000000..f1be7678 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0081_google_document_ai_warehouse_location_kms_key.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0081", + "name": "Ensure Document AI Warehouse Location is configured to use a Customer Managed Key (CMK)", + "description": "Ensure Document AI Warehouse Location is configured to use a Customer Managed Key (CMK)", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + "evaluators": [ + { + "id": "kms_key_set", + "description": "google_document_ai_warehouse_location.kms_key must be set", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_document_ai_warehouse_location", + "terraform_resource_attribute": "kms_key" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "kms_key_set" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0082_google_notebooks_instance_kms_key.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0082_google_notebooks_instance_kms_key.json new file mode 100644 index 00000000..284a3b6c --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0082_google_notebooks_instance_kms_key.json @@ -0,0 +1,44 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0082", + "name": "Ensure Vertex AI instance disks are encrypted with a Customer Managed Key (CMK)", + "description": "Ensure Vertex AI instance disks are encrypted with a Customer Managed Key (CMK)", + "tags": [ + "cloud:gcp", + "encryption" + ], + "remediation": "Set google_notebooks_instance.disk_encryption to \"CMEK\" and supply a kms_key." + }, + "evaluators": [ + { + "id": "kms_key_is_set", + "description": "google_notebooks_instance.kms_key is present and non-empty", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_notebooks_instance", + "terraform_resource_attribute": "kms_key" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + }, + { + "id": "disk_encryption_is_cmek", + "description": "google_notebooks_instance.disk_encryption equals CMEK", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_notebooks_instance", + "terraform_resource_attribute": "disk_encryption" + }, + "condition": { + "type": "Equals", + "value": "CMEK", + "error_tolerance": 1 + } + } + ], + "eval_expression": "kms_key_is_set && disk_encryption_is_cmek" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0083_google_kms_crypto_key_iam_member.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0083_google_kms_crypto_key_iam_member.json new file mode 100644 index 00000000..b056a4cd --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0083_google_kms_crypto_key_iam_member.json @@ -0,0 +1,62 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0083", + "name": "Ensure KMS policy should not allow public access", + "description": "Ensure KMS policy should not allow public access", + "tags": [ + "cloud:gcp", + "iam" + ], + "remediation": "Remove 'allUsers' and 'allAuthenticatedUsers' from the member/members of every google_kms_crypto_key_iam_member and google_kms_crypto_key_iam_binding." + }, + "evaluators": [ + { + "id": "crypto_key_iam_member_not_public", + "description": "google_kms_crypto_key_iam_member.member is neither allUsers nor allAuthenticatedUsers", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_kms_crypto_key_iam_member", + "terraform_resource_attribute": "member" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "allUsers", + "allAuthenticatedUsers" + ], + "error_tolerance": 1 + } + }, + { + "id": "crypto_key_iam_binding_no_all_users", + "description": "google_kms_crypto_key_iam_binding.members does not contain allUsers", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_kms_crypto_key_iam_binding", + "terraform_resource_attribute": "members" + }, + "condition": { + "type": "NotContains", + "value": "allUsers", + "error_tolerance": 1 + } + }, + { + "id": "crypto_key_iam_binding_no_all_authenticated_users", + "description": "google_kms_crypto_key_iam_binding.members does not contain allAuthenticatedUsers", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_kms_crypto_key_iam_binding", + "terraform_resource_attribute": "members" + }, + "condition": { + "type": "NotContains", + "value": "allAuthenticatedUsers", + "error_tolerance": 1 + } + } + ], + "eval_expression": "crypto_key_iam_member_not_public && crypto_key_iam_binding_no_all_users && crypto_key_iam_binding_no_all_authenticated_users" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0084_google_notebooks_instance_no_public_ip.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0084_google_notebooks_instance_no_public_ip.json new file mode 100644 index 00000000..c74a8f53 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0084_google_notebooks_instance_no_public_ip.json @@ -0,0 +1,31 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0084", + "name": "Ensure Vertex AI instances are private", + "description": "Ensure Vertex AI instances are private", + "tags": [ + "cloud:gcp", + "general_security" + ], + "remediation": "Set no_public_ip = true on the google_notebooks_instance." + }, + "evaluators": [ + { + "id": "no_public_ip_enabled", + "description": "google_notebooks_instance.no_public_ip is true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_notebooks_instance", + "terraform_resource_attribute": "no_public_ip" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "no_public_ip_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0085_google_spanner_database_enable_drop_protection.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0085_google_spanner_database_enable_drop_protection.json new file mode 100644 index 00000000..bb903add --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0085_google_spanner_database_enable_drop_protection.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0085", + "name": "Ensure Spanner Database has drop protection enabled", + "description": "Ensure Spanner Database has drop protection enabled", + "tags": [ + "cloud:gcp", + "general_security" + ] + }, + "evaluators": [ + { + "id": "spanner_drop_protection_enabled", + "description": "google_spanner_database.enable_drop_protection must be true. A boolean is compared with Equals, and null or absent fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_spanner_database", + "terraform_resource_attribute": "enable_drop_protection" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "spanner_drop_protection_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0086_google_spanner_database_encryption_config_kms_key_name.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0086_google_spanner_database_encryption_config_kms_key_name.json new file mode 100644 index 00000000..1049c30c --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0086_google_spanner_database_encryption_config_kms_key_name.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0086", + "name": "Ensure Spanner Database is encrypted with Customer Supplied Encryption Keys (CSEK)", + "description": "Ensure Spanner Database is encrypted with Customer Supplied Encryption Keys (CSEK)", + "tags": [ + "cloud:gcp", + "encryption" + ] + }, + "evaluators": [ + { + "id": "spanner_encryption_config_kms_key", + "description": "google_spanner_database.encryption_config.*.kms_key_name must be a non-empty string. An absent or empty encryption_config block makes the wildcard path miss (severity 2, untolerated) and fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_spanner_database", + "terraform_resource_attribute": "encryption_config.*.kms_key_name" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "spanner_encryption_config_kms_key" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0087_google_storage_bucket_public_access_prevention.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0087_google_storage_bucket_public_access_prevention.json new file mode 100644 index 00000000..1dda3a2f --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0087_google_storage_bucket_public_access_prevention.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0087", + "name": "Ensure public access prevention is enforced on Cloud Storage bucket", + "description": "Ensure public access prevention is enforced on Cloud Storage bucket", + "tags": [ + "cloud:gcp", + "general_security" + ] + }, + "evaluators": [ + { + "id": "public_access_prevention_enforced", + "description": "google_storage_bucket.public_access_prevention must equal 'enforced'. A bucket that leaves the attribute out (so the plan carries no value, or carries 'inherited') is a severity-2 miss and fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_storage_bucket", + "terraform_resource_attribute": "public_access_prevention" + }, + "condition": { + "type": "Equals", + "value": "enforced", + "error_tolerance": 1 + } + } + ], + "eval_expression": "public_access_prevention_enforced" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0088_google_storage_bucket_versioning_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0088_google_storage_bucket_versioning_enabled.json new file mode 100644 index 00000000..8ecb6ef1 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0088_google_storage_bucket_versioning_enabled.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0088", + "name": "Ensure Cloud storage has versioning enabled", + "description": "Ensure Cloud storage has versioning enabled", + "tags": [ + "cloud:gcp", + "logging" + ] + }, + "evaluators": [ + { + "id": "bucket_versioning_enabled", + "description": "google_storage_bucket versioning.*.enabled must be true. versioning is a block list in the plan; an absent or empty block is a severity-2 miss and fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "google_storage_bucket", + "terraform_resource_attribute": "versioning.*.enabled" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "bucket_versioning_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0089_kubernetes_pod_spec_container_env_name.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0089_kubernetes_pod_spec_container_env_name.json new file mode 100644 index 00000000..9ca5d096 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0089_kubernetes_pod_spec_container_env_name.json @@ -0,0 +1,72 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0089", + "name": "Do not admit privileged containers", + "description": "Do not admit privileged containers", + "tags": [ + "cloud:kubernetes", + "general_security" + ] + }, + "evaluators": [ + { + "id": "pod_no_gitsync_git_env", + "description": "No container of a kubernetes_pod declares an env entry named GITSYNC_GIT. NotEquals passes on null, so containers with no env block do not fail.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_pod", + "terraform_resource_attribute": "spec.0.container.*.env.*.name" + }, + "condition": { + "type": "NotEquals", + "value": "GITSYNC_GIT", + "error_tolerance": 1 + } + }, + { + "id": "pod_v1_no_gitsync_git_env", + "description": "No container of a kubernetes_pod_v1 declares an env entry named GITSYNC_GIT. NotEquals passes on null, so containers with no env block do not fail.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_pod_v1", + "terraform_resource_attribute": "spec.0.container.*.env.*.name" + }, + "condition": { + "type": "NotEquals", + "value": "GITSYNC_GIT", + "error_tolerance": 1 + } + }, + { + "id": "deployment_no_gitsync_git_env", + "description": "No container of a kubernetes_deployment declares an env entry named GITSYNC_GIT. NotEquals passes on null, so containers with no env block do not fail.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_deployment", + "terraform_resource_attribute": "spec.0.template.0.spec.0.container.*.env.*.name" + }, + "condition": { + "type": "NotEquals", + "value": "GITSYNC_GIT", + "error_tolerance": 1 + } + }, + { + "id": "deployment_v1_no_gitsync_git_env", + "description": "No container of a kubernetes_deployment_v1 declares an env entry named GITSYNC_GIT. NotEquals passes on null, so containers with no env block do not fail.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_deployment_v1", + "terraform_resource_attribute": "spec.0.template.0.spec.0.container.*.env.*.name" + }, + "condition": { + "type": "NotEquals", + "value": "GITSYNC_GIT", + "error_tolerance": 1 + } + } + ], + "eval_expression": "pod_no_gitsync_git_env && pod_v1_no_gitsync_git_env && deployment_no_gitsync_git_env && deployment_v1_no_gitsync_git_env" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0090_kubernetes_pod_spec_container_image_pull_policy.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0090_kubernetes_pod_spec_container_image_pull_policy.json new file mode 100644 index 00000000..aecd9bec --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0090_kubernetes_pod_spec_container_image_pull_policy.json @@ -0,0 +1,72 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0090", + "name": "Image Pull Policy should be Always", + "description": "Image Pull Policy should be Always", + "tags": [ + "cloud:kubernetes", + "general_security" + ] + }, + "evaluators": [ + { + "id": "pod_image_pull_policy_always", + "description": "Every container of a kubernetes_pod sets image_pull_policy = Always. An unset policy is null in the plan and fails Equals, which is the right verdict for the common case of a tagged, non-latest image.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_pod", + "terraform_resource_attribute": "spec.0.container.*.image_pull_policy" + }, + "condition": { + "type": "Equals", + "value": "Always", + "error_tolerance": 1 + } + }, + { + "id": "pod_v1_image_pull_policy_always", + "description": "Every container of a kubernetes_pod_v1 sets image_pull_policy = Always. An unset policy is null in the plan and fails Equals, which is the right verdict for the common case of a tagged, non-latest image.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_pod_v1", + "terraform_resource_attribute": "spec.0.container.*.image_pull_policy" + }, + "condition": { + "type": "Equals", + "value": "Always", + "error_tolerance": 1 + } + }, + { + "id": "deployment_image_pull_policy_always", + "description": "Every container of a kubernetes_deployment sets image_pull_policy = Always. An unset policy is null in the plan and fails Equals, which is the right verdict for the common case of a tagged, non-latest image.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_deployment", + "terraform_resource_attribute": "spec.0.template.0.spec.0.container.*.image_pull_policy" + }, + "condition": { + "type": "Equals", + "value": "Always", + "error_tolerance": 1 + } + }, + { + "id": "deployment_v1_image_pull_policy_always", + "description": "Every container of a kubernetes_deployment_v1 sets image_pull_policy = Always. An unset policy is null in the plan and fails Equals, which is the right verdict for the common case of a tagged, non-latest image.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_deployment_v1", + "terraform_resource_attribute": "spec.0.template.0.spec.0.container.*.image_pull_policy" + }, + "condition": { + "type": "Equals", + "value": "Always", + "error_tolerance": 1 + } + } + ], + "eval_expression": "pod_image_pull_policy_always && pod_v1_image_pull_policy_always && deployment_image_pull_policy_always && deployment_v1_image_pull_policy_always" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0091_kubernetes_pod_spec_container_security_context_privileged.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0091_kubernetes_pod_spec_container_security_context_privileged.json new file mode 100644 index 00000000..d05b44ea --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0091_kubernetes_pod_spec_container_security_context_privileged.json @@ -0,0 +1,72 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0091", + "name": "Do not admit privileged containers", + "description": "Do not admit privileged containers", + "tags": [ + "cloud:kubernetes", + "general_security" + ] + }, + "evaluators": [ + { + "id": "pod_not_privileged", + "description": "No container of a kubernetes_pod sets security_context.privileged = true. NotEquals passes on null, so a container with no security_context, or one that leaves privileged unset, passes.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_pod", + "terraform_resource_attribute": "spec.0.container.*.security_context.0.privileged" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 1 + } + }, + { + "id": "pod_v1_not_privileged", + "description": "No container of a kubernetes_pod_v1 sets security_context.privileged = true. NotEquals passes on null, so a container with no security_context, or one that leaves privileged unset, passes.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_pod_v1", + "terraform_resource_attribute": "spec.0.container.*.security_context.0.privileged" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 1 + } + }, + { + "id": "deployment_not_privileged", + "description": "No container of a kubernetes_deployment sets security_context.privileged = true. NotEquals passes on null, so a container with no security_context, or one that leaves privileged unset, passes.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_deployment", + "terraform_resource_attribute": "spec.0.template.0.spec.0.container.*.security_context.0.privileged" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 1 + } + }, + { + "id": "deployment_v1_not_privileged", + "description": "No container of a kubernetes_deployment_v1 sets security_context.privileged = true. NotEquals passes on null, so a container with no security_context, or one that leaves privileged unset, passes.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_deployment_v1", + "terraform_resource_attribute": "spec.0.template.0.spec.0.container.*.security_context.0.privileged" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "pod_not_privileged && pod_v1_not_privileged && deployment_not_privileged && deployment_v1_not_privileged" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0092_kubernetes_pod_spec_container_security_context_capabilities_add.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0092_kubernetes_pod_spec_container_security_context_capabilities_add.json new file mode 100644 index 00000000..e24d7ffe --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0092_kubernetes_pod_spec_container_security_context_capabilities_add.json @@ -0,0 +1,68 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0092", + "name": "Minimize the admission of containers with added capability", + "description": "Minimize the admission of containers with added capability", + "tags": [ + "cloud:kubernetes", + "general_security" + ] + }, + "evaluators": [ + { + "id": "pod_no_added_capabilities", + "description": "Every container of kubernetes_pod leaves security_context.capabilities.add empty. Path spec.*.container.*.security_context.*.capabilities.*.add yields one value per container: null when the container has no security_context or no capabilities block, [] when add is unset, and the capability list when it is set. IsEmpty passes on null and [] and fails on a non-empty list, so any added capability fails the plan.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_pod", + "terraform_resource_attribute": "spec.*.container.*.security_context.*.capabilities.*.add" + }, + "condition": { + "type": "IsEmpty", + "error_tolerance": 1 + } + }, + { + "id": "pod_v1_no_added_capabilities", + "description": "Every container of kubernetes_pod_v1 leaves security_context.capabilities.add empty. Path spec.*.container.*.security_context.*.capabilities.*.add yields one value per container: null when the container has no security_context or no capabilities block, [] when add is unset, and the capability list when it is set. IsEmpty passes on null and [] and fails on a non-empty list, so any added capability fails the plan.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_pod_v1", + "terraform_resource_attribute": "spec.*.container.*.security_context.*.capabilities.*.add" + }, + "condition": { + "type": "IsEmpty", + "error_tolerance": 1 + } + }, + { + "id": "deployment_no_added_capabilities", + "description": "Every container of kubernetes_deployment leaves security_context.capabilities.add empty. Path spec.*.template.*.spec.*.container.*.security_context.*.capabilities.*.add yields one value per container: null when the container has no security_context or no capabilities block, [] when add is unset, and the capability list when it is set. IsEmpty passes on null and [] and fails on a non-empty list, so any added capability fails the plan.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_deployment", + "terraform_resource_attribute": "spec.*.template.*.spec.*.container.*.security_context.*.capabilities.*.add" + }, + "condition": { + "type": "IsEmpty", + "error_tolerance": 1 + } + }, + { + "id": "deployment_v1_no_added_capabilities", + "description": "Every container of kubernetes_deployment_v1 leaves security_context.capabilities.add empty. Path spec.*.template.*.spec.*.container.*.security_context.*.capabilities.*.add yields one value per container: null when the container has no security_context or no capabilities block, [] when add is unset, and the capability list when it is set. IsEmpty passes on null and [] and fails on a non-empty list, so any added capability fails the plan.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_deployment_v1", + "terraform_resource_attribute": "spec.*.template.*.spec.*.container.*.security_context.*.capabilities.*.add" + }, + "condition": { + "type": "IsEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "pod_no_added_capabilities && pod_v1_no_added_capabilities && deployment_no_added_capabilities && deployment_v1_no_added_capabilities" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0093_kubernetes_service_account_metadata_name.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0093_kubernetes_service_account_metadata_name.json new file mode 100644 index 00000000..0549278f --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0093_kubernetes_service_account_metadata_name.json @@ -0,0 +1,76 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0093", + "name": "Ensure that default service accounts are not actively used", + "description": "Ensure that default service accounts are not actively used", + "tags": [ + "cloud:kubernetes", + "general_security" + ] + }, + "evaluators": [ + { + "id": "service_account_name_not_default", + "description": "Guard: no kubernetes_service_account is named 'default'. Only the default service account is in scope, so this guard is OR-ed with the real check and lets every other account pass.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_service_account", + "terraform_resource_attribute": "metadata.0.name" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "default" + ], + "error_tolerance": 1 + } + }, + { + "id": "service_account_automount_disabled", + "description": "kubernetes_service_account sets automount_service_account_token to false; null or true fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_service_account", + "terraform_resource_attribute": "automount_service_account_token" + }, + "condition": { + "type": "Equals", + "value": false, + "error_tolerance": 1 + } + }, + { + "id": "service_account_v1_name_not_default", + "description": "Same guard for the kubernetes_service_account_v1 alias", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_service_account_v1", + "terraform_resource_attribute": "metadata.0.name" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "default" + ], + "error_tolerance": 1 + } + }, + { + "id": "service_account_v1_automount_disabled", + "description": "Same check for the kubernetes_service_account_v1 alias", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "kubernetes_service_account_v1", + "terraform_resource_attribute": "automount_service_account_token" + }, + "condition": { + "type": "Equals", + "value": false, + "error_tolerance": 1 + } + } + ], + "eval_expression": "(service_account_name_not_default || service_account_automount_disabled) && (service_account_v1_name_not_default || service_account_v1_automount_disabled)" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0094_linode_firewall_inbound_policy.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0094_linode_firewall_inbound_policy.json new file mode 100644 index 00000000..a4e2d565 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0094_linode_firewall_inbound_policy.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0094", + "name": "Ensure Inbound Firewall Policy is not set to ACCEPT", + "description": "Ensure Inbound Firewall Policy is not set to ACCEPT", + "tags": [ + "cloud:linode", + "general_security" + ] + }, + "evaluators": [ + { + "id": "inbound_policy_is_drop", + "description": "linode_firewall.inbound_policy must be DROP", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "linode_firewall", + "terraform_resource_attribute": "inbound_policy" + }, + "condition": { + "type": "Equals", + "value": "DROP", + "error_tolerance": 1 + } + } + ], + "eval_expression": "inbound_policy_is_drop" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0095_oci_file_storage_export_options_identity_squash.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0095_oci_file_storage_export_options_identity_squash.json new file mode 100644 index 00000000..a56689b4 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0095_oci_file_storage_export_options_identity_squash.json @@ -0,0 +1,35 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0095", + "name": "Ensure File Storage File System access is restricted to root users", + "description": "Ensure File Storage File System access is restricted to root users", + "tags": [ + "cloud:oci", + "general_security" + ], + "remediation": "Avoid identity_squash = \"ROOT\" on oci_file_storage_export export_options; if root squashing is required, pin anonymous_uid and anonymous_gid to 65534." + }, + "evaluators": [ + { + "id": "no_root_identity_squash", + "description": "No export_options entry squashes to ROOT. NotContainedIn with a list passes on a null input, so an entry that omits identity_squash (padded to null by the wildcard) passes.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "oci_file_storage_export", + "terraform_resource_attribute": "export_options.*.identity_squash" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "ROOT", + "root", + "Root" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "no_root_identity_squash" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0096_oci_core_instance_launch_options_is_pv_encryption_in_transit_enabled.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0096_oci_core_instance_launch_options_is_pv_encryption_in_transit_enabled.json new file mode 100644 index 00000000..13073535 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0096_oci_core_instance_launch_options_is_pv_encryption_in_transit_enabled.json @@ -0,0 +1,31 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0096", + "name": "Ensure OCI Compute Instance boot volume has in-transit data encryption enabled", + "description": "Ensure OCI Compute Instance boot volume has in-transit data encryption enabled", + "tags": [ + "cloud:oci", + "encryption" + ], + "remediation": "Set launch_options { is_pv_encryption_in_transit_enabled = true } on oci_core_instance." + }, + "evaluators": [ + { + "id": "boot_volume_in_transit_encryption", + "description": "launch_options.0.is_pv_encryption_in_transit_enabled must be true. An absent or null launch_options block makes the indexed path a severity-2 miss, which fails at error_tolerance 1.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "oci_core_instance", + "terraform_resource_attribute": "launch_options.0.is_pv_encryption_in_transit_enabled" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "boot_volume_in_transit_encryption" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0097_oci_identity_authentication_policy_password_is_lowercase_characters_re.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0097_oci_identity_authentication_policy_password_is_lowercase_characters_re.json new file mode 100644 index 00000000..b0d69e49 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0097_oci_identity_authentication_policy_password_is_lowercase_characters_re.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0097", + "name": "OCI IAM password policy - must contain lower case", + "description": "OCI IAM password policy - must contain lower case", + "tags": [ + "cloud:oci", + "general_security" + ] + }, + "evaluators": [ + { + "id": "lowercase_required", + "description": "oci_identity_authentication_policy.password_policy.0.is_lowercase_characters_required must be true. It is a boolean attribute, so Equals true rather than IsNotEmpty; error_tolerance 1 means an absent password_policy block, or a block without the flag, is a severity-2 attribute miss and still fails.", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "oci_identity_authentication_policy", + "terraform_resource_attribute": "password_policy.0.is_lowercase_characters_required" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "lowercase_required" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0098_panos_ipsec_crypto_profile_protocol.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0098_panos_ipsec_crypto_profile_protocol.json new file mode 100644 index 00000000..097f29cc --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0098_panos_ipsec_crypto_profile_protocol.json @@ -0,0 +1,48 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0098", + "name": "Ensure IPsec profiles do not specify use of insecure protocols", + "description": "Ensure IPsec profiles do not specify use of insecure protocols", + "tags": [ + "cloud:panos", + "networking" + ] + }, + "evaluators": [ + { + "id": "ipsec_crypto_profile_protocol", + "description": "panos_ipsec_crypto_profile.protocol must not be the insecure 'ah' protocol", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "panos_ipsec_crypto_profile", + "terraform_resource_attribute": "protocol" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "ah" + ], + "error_tolerance": 1 + } + }, + { + "id": "panorama_ipsec_crypto_profile_protocol", + "description": "panos_panorama_ipsec_crypto_profile.protocol must not be the insecure 'ah' protocol", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "panos_panorama_ipsec_crypto_profile", + "terraform_resource_attribute": "protocol" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "ah" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "ipsec_crypto_profile_protocol && panorama_ipsec_crypto_profile_protocol" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0099_panos_management_profile_telnet.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0099_panos_management_profile_telnet.json new file mode 100644 index 00000000..68bb6d6d --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0099_panos_management_profile_telnet.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0099", + "name": "Ensure plain-text management Telnet is not enabled for an Interface Management Profile", + "description": "Ensure plain-text management Telnet is not enabled for an Interface Management Profile", + "tags": [ + "cloud:panos", + "networking" + ] + }, + "evaluators": [ + { + "id": "management_profile_telnet_disabled", + "description": "panos_management_profile.telnet must not be true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "panos_management_profile", + "terraform_resource_attribute": "telnet" + }, + "condition": { + "type": "NotEquals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "management_profile_telnet_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0100_tencentcloud_clb_listener_protocol.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0100_tencentcloud_clb_listener_protocol.json new file mode 100644 index 00000000..3bc1ae98 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0100_tencentcloud_clb_listener_protocol.json @@ -0,0 +1,34 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0100", + "name": "Ensure Tencent Cloud CLBs use modern, encrypted protocols", + "description": "Ensure Tencent Cloud CLBs use modern, encrypted protocols", + "tags": [ + "cloud:tencentcloud", + "networking" + ] + }, + "evaluators": [ + { + "id": "listener_protocol_not_plaintext", + "description": "tencentcloud_clb_listener protocol must not be TCP, UDP or HTTP", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "tencentcloud_clb_listener", + "terraform_resource_attribute": "protocol" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + "TCP", + "UDP", + "HTTP" + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "listener_protocol_not_plaintext" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0101_tencentcloud_cbs_storage_encrypt.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0101_tencentcloud_cbs_storage_encrypt.json new file mode 100644 index 00000000..6dc4d311 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0101_tencentcloud_cbs_storage_encrypt.json @@ -0,0 +1,30 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0101", + "name": "Ensure Tencent Cloud CBS is encrypted", + "description": "Ensure Tencent Cloud CBS is encrypted", + "tags": [ + "cloud:tencentcloud", + "encryption" + ] + }, + "evaluators": [ + { + "id": "cbs_encrypt_enabled", + "description": "tencentcloud_cbs_storage must set encrypt = true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "tencentcloud_cbs_storage", + "terraform_resource_attribute": "encrypt" + }, + "condition": { + "type": "Equals", + "value": true, + "error_tolerance": 1 + } + } + ], + "eval_expression": "cbs_encrypt_enabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0102_tencentcloud_instance_disable_monitor_service.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0102_tencentcloud_instance_disable_monitor_service.json new file mode 100644 index 00000000..1f310b93 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0102_tencentcloud_instance_disable_monitor_service.json @@ -0,0 +1,32 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0102", + "name": "Ensure Tencent Cloud CVM monitor service is enabled", + "description": "Ensure Tencent Cloud CVM monitor service is enabled", + "tags": [ + "cloud:tencentcloud", + "logging" + ] + }, + "evaluators": [ + { + "id": "monitor_service_not_disabled", + "description": "tencentcloud_instance must not set disable_monitor_service = true", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "tencentcloud_instance", + "terraform_resource_attribute": "disable_monitor_service" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + true + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "monitor_service_not_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0103_yandex_kubernetes_cluster_master_public_ip.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0103_yandex_kubernetes_cluster_master_public_ip.json new file mode 100644 index 00000000..d9122276 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0103_yandex_kubernetes_cluster_master_public_ip.json @@ -0,0 +1,32 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0103", + "name": "Ensure Kubernetes cluster does not have public IP address.", + "description": "Ensure Kubernetes cluster does not have public IP address.", + "tags": [ + "cloud:yandex", + "networking" + ] + }, + "evaluators": [ + { + "id": "master_public_ip_disabled", + "description": "master[0].public_ip must not be true on a yandex_kubernetes_cluster", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "yandex_kubernetes_cluster", + "terraform_resource_attribute": "master.0.public_ip" + }, + "condition": { + "type": "NotContainedIn", + "value": [ + true + ], + "error_tolerance": 1 + } + } + ], + "eval_expression": "master_public_ip_disabled" +} diff --git a/src/tirith/packs/terraform-baseline/policies/SG_TF_0104_yandex_kms_symmetric_key_rotation_period.json b/src/tirith/packs/terraform-baseline/policies/SG_TF_0104_yandex_kms_symmetric_key_rotation_period.json new file mode 100644 index 00000000..d9eaded4 --- /dev/null +++ b/src/tirith/packs/terraform-baseline/policies/SG_TF_0104_yandex_kms_symmetric_key_rotation_period.json @@ -0,0 +1,29 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/terraform_plan", + "id": "SG_TF_0104", + "name": "Ensure KMS symmetric key is rotated.", + "description": "Ensure KMS symmetric key is rotated.", + "tags": [ + "cloud:yandex", + "encryption" + ] + }, + "evaluators": [ + { + "id": "rotation_period_set", + "description": "yandex_kms_symmetric_key must set a non-empty rotation_period", + "provider_args": { + "operation_type": "attribute", + "terraform_resource_type": "yandex_kms_symmetric_key", + "terraform_resource_attribute": "rotation_period" + }, + "condition": { + "type": "IsNotEmpty", + "error_tolerance": 1 + } + } + ], + "eval_expression": "rotation_period_set" +} diff --git a/src/tirith/prettyprinter.py b/src/tirith/prettyprinter.py index 599f4100..f88eb985 100644 --- a/src/tirith/prettyprinter.py +++ b/src/tirith/prettyprinter.py @@ -126,3 +126,68 @@ def pretty_print_result_dict(final_result_dict: Dict) -> None: print(TermStyle.skipped("= Skipped final evaluator")) else: print(TermStyle.fail("✘ Failed final evaluation")) + + +def _policy_label(policy_result: Dict) -> str: + """``, falling back to the file name when meta says nothing.""" + name = policy_result.get("policy", "") + meta = policy_result.get("meta") or {} + title = meta.get("name") or meta.get("id") or "" + return f"{name} — {title}" if title else name + + +def pretty_print_policy_set_result(set_result_dict: Dict, verbose: bool = False) -> None: + """ + Print the aggregate result of running many policies against one input. + + Printing every policy in full does not scale: a pack has hundreds, and almost all of them + skip, because a check only applies to plans that touch the resource it names. So failures + are printed in full -- they are the reason anyone ran this -- and everything else is counted. + `verbose` restores the full per-policy detail. + + :param set_result_dict: Result dictionary generated by `start_policy_set_evaluation` + :param verbose: Print every policy in full, not just the failures + """ + policies = set_result_dict.get("policies", []) + summary = set_result_dict.get("summary", {}) + + errored = [p for p in policies if "final_result" not in p] + + for policy_result in policies: + if not verbose and policy_result.get("final_result") is not False: + continue + print(TermStyle.str_with_style(_policy_label(policy_result), TermStyle.BOLD)) + if "final_result" in policy_result: + pretty_print_result_dict(policy_result) + else: + for error in policy_result.get("errors", []): + print(TermStyle.fail(f"- {error}")) + print() + + if errored and not verbose: + print(TermStyle.fail(f"Could not evaluate {len(errored)} policy/policies:")) + for policy_result in errored: + for error in policy_result.get("errors", []): + print(TermStyle.fail(f"- {policy_result.get('policy', '')}: {error}")) + print() + + print( + f"{summary.get('total', 0)} policies · " + f"{TermStyle.green(str(summary.get('passed', 0)) + ' passed')} · " + f"{TermStyle.red(str(summary.get('failed', 0)) + ' failed')} · " + f"{TermStyle.grey(str(summary.get('skipped', 0)) + ' skipped')}" + + (f" · {TermStyle.fail(str(summary.get('errored', 0)) + ' errored')}" if summary.get("errored") else "") + ) + # Said explicitly because it is the one number that surprises people: a skipped policy found + # no resource of the type it checks, which is the normal outcome for most of a large pack. + if summary.get("skipped"): + print(TermStyle.grey("Skipped policies found no resource of the type they check.")) + print() + + final_result = set_result_dict.get("final_result") + if final_result is True: + print(TermStyle.success("✔ No policy failed")) + elif final_result is False: + print(TermStyle.fail(f"✘ {summary.get('failed', 0)} policy/policies failed")) + else: + print(TermStyle.skipped("= No policy reached a verdict")) diff --git a/tests/cli/test_policy_sets.py b/tests/cli/test_policy_sets.py new file mode 100644 index 00000000..b6e0be91 --- /dev/null +++ b/tests/cli/test_policy_sets.py @@ -0,0 +1,196 @@ +""" +Running many policies in one invocation: directories and `--pack`. + +Two contracts are asserted here, and they pull in opposite directions. + +The first is that nothing moved. `-policy-path ` is the surface every existing caller uses +and its result document is byte-pinned elsewhere, so a set run has to be a *different* shape +reached by a different request. The rule is that the shape follows how the run was asked for -- +a directory or a `--pack` is a set, a file is not -- and not how many policies happened to match, +so a directory holding one policy still reports as a set. + +The second is that `skipped` is not a failure. A policy only applies to plans that touch the +resource it names, so across any pack of real size most policies skip. If a skip counted as an +error, every pack run would be red no matter how compliant the infrastructure was, and the exit +code would carry no information at all. +""" + +import json +import os +import sys + +import pytest + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "src")) + +from tirith import packs +from tirith.cli import main +from tirith.status import ExitStatus + +PLAN = { + "format_version": "1.2", + "terraform_version": "1.5.7", + "resource_changes": [ + { + "address": "aws_instance.app", + "mode": "managed", + "type": "aws_instance", + "name": "app", + "change": { + "actions": ["create"], + "before": None, + "after": {"instance_type": "m5.24xlarge"}, + "after_sensitive": {}, + }, + } + ], +} + + +def _policy(policy_id, resource_type, value): + return { + "meta": { + "id": policy_id, + "name": policy_id, + "required_provider": "stackguardian/terraform_plan", + "version": "v1", + }, + "evaluators": [ + { + "id": "ev", + "condition": {"type": "Equals", "value": value, "error_tolerance": 1}, + "provider_args": { + "operation_type": "attribute", + "terraform_resource_attribute": "instance_type", + "terraform_resource_type": resource_type, + }, + } + ], + "eval_expression": "ev", + } + + +def _tree(tmp_path, policies): + policy_dir = tmp_path / "policies" + policy_dir.mkdir() + for policy in policies: + (policy_dir / f"{policy['meta']['id']}.json").write_text(json.dumps(policy)) + plan_path = tmp_path / "plan.json" + plan_path.write_text(json.dumps(PLAN)) + return ["-policy-path", str(policy_dir), "-input-path", str(plan_path)] + + +def _run_json(capsys, args): + main(args + ["--json"]) + return json.loads(capsys.readouterr().out) + + +def test_a_directory_reports_a_summary(tmp_path, capsys): + args = _tree( + tmp_path, + [ + _policy("passes", "aws_instance", "m5.24xlarge"), + _policy("fails", "aws_instance", "t3.micro"), + # No aws_db_instance in the plan, so this one skips rather than failing. + _policy("skips", "aws_db_instance", "t3.micro"), + ], + ) + result = _run_json(capsys, args) + assert result["summary"] == {"total": 3, "passed": 1, "failed": 1, "skipped": 1, "errored": 0} + assert result["final_result"] is False + assert [p["policy"] for p in result["policies"]] == ["fails.json", "passes.json", "skips.json"] + + +def test_each_policy_keeps_its_own_result_document(tmp_path, capsys): + args = _tree(tmp_path, [_policy("passes", "aws_instance", "m5.24xlarge")]) + result = _run_json(capsys, args) + (only,) = result["policies"] + # Everything a single-policy run returns is still there, plus the name. + assert set(only) >= {"policy", "meta", "final_result", "evaluators", "errors", "eval_expression"} + + +def test_a_directory_of_one_is_still_a_set(tmp_path, capsys): + """The shape follows how the run was asked for, not how many policies matched.""" + args = _tree(tmp_path, [_policy("passes", "aws_instance", "m5.24xlarge")]) + result = _run_json(capsys, args) + assert "summary" in result + + +def test_a_single_file_is_not_a_set(tmp_path, capsys): + _tree(tmp_path, [_policy("passes", "aws_instance", "m5.24xlarge")]) + args = [ + "-policy-path", + str(tmp_path / "policies" / "passes.json"), + "-input-path", + str(tmp_path / "plan.json"), + ] + result = _run_json(capsys, args) + assert "summary" not in result + assert result["final_result"] is True + + +def test_skipped_policies_alone_are_one_not_three(tmp_path): + """ + Nothing reached a verdict, so tirith cannot tell you anything -- 1, not 3 and not 0. The same + rule the single-policy path applies to `final_result: None`. + """ + args = _tree(tmp_path, [_policy("skips", "aws_db_instance", "t3.micro")]) + assert main(args + ["--fail-on-error"]) == ExitStatus.ERROR + + +def test_skipped_policies_do_not_drag_a_passing_run_down(tmp_path): + args = _tree( + tmp_path, + [ + _policy("passes", "aws_instance", "m5.24xlarge"), + _policy("skips", "aws_db_instance", "t3.micro"), + ], + ) + assert main(args + ["--fail-on-error"]) == ExitStatus.SUCCESS + + +def test_one_failure_among_many_exits_three(tmp_path): + args = _tree( + tmp_path, + [ + _policy("passes", "aws_instance", "m5.24xlarge"), + _policy("fails", "aws_instance", "t3.micro"), + _policy("skips", "aws_db_instance", "t3.micro"), + ], + ) + assert main(args + ["--fail-on-error"]) == ExitStatus.ERROR_POLICY_FAILED + + +def test_a_set_still_exits_zero_without_fail_on_error(tmp_path): + args = _tree(tmp_path, [_policy("fails", "aws_instance", "t3.micro")]) + assert main(args) == ExitStatus.SUCCESS + + +def test_a_broken_policy_does_not_take_the_run_down(tmp_path, capsys): + args = _tree(tmp_path, [_policy("passes", "aws_instance", "m5.24xlarge")]) + (tmp_path / "policies" / "broken.json").write_text("{not json") + result = _run_json(capsys, args) + assert result["summary"]["errored"] == 1 + assert result["summary"]["passed"] == 1 + + +def test_an_unknown_pack_is_reported_not_raised(tmp_path): + args = _tree(tmp_path, []) + assert main(["--pack", "no-such-pack"] + args[2:]) == ExitStatus.ERROR + + +def test_list_packs_exits_zero(capsys): + assert main(["--list-packs"]) == ExitStatus.SUCCESS + assert capsys.readouterr().out + + +@pytest.mark.skipif(not packs.list_packs(), reason="no packs bundled") +def test_a_bundled_pack_runs(tmp_path, capsys): + plan_path = tmp_path / "plan.json" + plan_path.write_text(json.dumps(PLAN)) + pack = packs.list_packs()[0] + result = _run_json(capsys, ["--pack", pack.name, "-input-path", str(plan_path)]) + assert result["summary"]["total"] == len(packs.pack_policy_paths(pack)) + # The point of the summary: on a one-resource plan almost everything skips, and that is fine. + assert result["summary"]["skipped"] > 0 + assert all(p["policy"].startswith(f"{pack.name}/") for p in result["policies"]) diff --git a/tests/core/test_core.py b/tests/core/test_core.py index 858e8b06..6a2db275 100644 --- a/tests/core/test_core.py +++ b/tests/core/test_core.py @@ -215,3 +215,44 @@ def test_generate_evaluator_result_bare_provider_err_ignores_error_tolerance(): assert result["passed"] is False, "a malformed provider call must not be skipped" assert result["result"][0]["passed"] is False + + +@mark.parametrize( + "inputs,expected", + [ + # The defect: a tolerated miss arriving *after* a real failure used to overwrite it with + # the skip marker, so the verdict depended on the order the provider emitted resources. + # Reachable on any plan holding both a resource that violates the policy and one the + # provider cannot read -- a destroy, say, whose `after` is null. + ("fail_then_skip", False), + ("skip_then_fail", False), + # Pass-and-skip keeps the behaviour it has always had, in both orders: nothing was + # actually verified about the tolerated resource, so the check does not claim a pass. + ("pass_then_skip", None), + ("skip_then_pass", None), + ], +) +@mark.passing +def test_generate_evaluator_result_skip_does_not_erase_a_failure(inputs, expected): + """A tolerated provider miss must not overwrite a verdict a sibling input already produced.""" + evaluator_obj = { + "id": "test_evaluator", + "provider_args": {"operation_type": "attribute", "key": "value"}, + "condition": {"type": "Equals", "value": "expected_value", "error_tolerance": 1}, + } + + skip = {"value": ProviderError(severity_value=1), "err": "Resource type not found"} + fail = {"value": "something_else"} + passes = {"value": "resource1"} # the one value MockEvaluator passes + provider_inputs = { + "fail_then_skip": [fail, skip], + "skip_then_fail": [skip, fail], + "pass_then_skip": [passes, skip], + "skip_then_pass": [skip, passes], + }[inputs] + + with patch("tirith.core.core.get_evaluator_inputs_from_provider_inputs", return_value=provider_inputs): + with patch("tirith.core.core.EVALUATORS_DICT", {"Equals": MockEvaluator}): + result = generate_evaluator_result(evaluator_obj, {}, "test_provider") + + assert result["passed"] is expected diff --git a/tests/packs/fixtures/SG_TF_0001.compliant.json b/tests/packs/fixtures/SG_TF_0001.compliant.json new file mode 100644 index 00000000..38874592 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0001.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "alicloud_kms_key.test", + "mode": "managed", + "type": "alicloud_kms_key", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "automatic_rotation": "Enabled" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0001.violating.json b/tests/packs/fixtures/SG_TF_0001.violating.json new file mode 100644 index 00000000..4e96bf80 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0001.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "alicloud_kms_key.test", + "mode": "managed", + "type": "alicloud_kms_key", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "automatic_rotation": "prefix-Enabled-suffix" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0002.compliant.json b/tests/packs/fixtures/SG_TF_0002.compliant.json new file mode 100644 index 00000000..b5bd08be --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0002.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "alicloud_disk.test", + "mode": "managed", + "type": "alicloud_disk", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "encrypted": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0002.violating.json b/tests/packs/fixtures/SG_TF_0002.violating.json new file mode 100644 index 00000000..2aefe7da --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0002.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "alicloud_disk.test", + "mode": "managed", + "type": "alicloud_disk", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "encrypted": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0003.compliant.json b/tests/packs/fixtures/SG_TF_0003.compliant.json new file mode 100644 index 00000000..7086c118 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0003.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "alicloud_ram_account_password_policy.test", + "mode": "managed", + "type": "alicloud_ram_account_password_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "minimum_password_length": 14 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0003.violating.json b/tests/packs/fixtures/SG_TF_0003.violating.json new file mode 100644 index 00000000..ca6f4335 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0003.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "alicloud_ram_account_password_policy.test", + "mode": "managed", + "type": "alicloud_ram_account_password_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "minimum_password_length": 13 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0004.compliant.json b/tests/packs/fixtures/SG_TF_0004.compliant.json new file mode 100644 index 00000000..1b4b16a4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0004.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "alicloud_ram_account_password_policy.test", + "mode": "managed", + "type": "alicloud_ram_account_password_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "max_password_age": 1 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0004.violating.json b/tests/packs/fixtures/SG_TF_0004.violating.json new file mode 100644 index 00000000..3ebe31d3 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0004.violating.json @@ -0,0 +1,26 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "alicloud_ram_account_password_policy.test", + "mode": "managed", + "type": "alicloud_ram_account_password_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "max_password_age": [ + 0, + 90 + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0005.compliant.json b/tests/packs/fixtures/SG_TF_0005.compliant.json new file mode 100644 index 00000000..6194878a --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0005.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "alicloud_ram_account_password_policy.test", + "mode": "managed", + "type": "alicloud_ram_account_password_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "require_uppercase_characters": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0005.violating.json b/tests/packs/fixtures/SG_TF_0005.violating.json new file mode 100644 index 00000000..121096ff --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0005.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "alicloud_ram_account_password_policy.test", + "mode": "managed", + "type": "alicloud_ram_account_password_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "require_uppercase_characters": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0006.compliant.json b/tests/packs/fixtures/SG_TF_0006.compliant.json new file mode 100644 index 00000000..86f4a594 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0006.compliant.json @@ -0,0 +1,22 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_bucket.filler", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "filler", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "id": "filler" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0006.violating.json b/tests/packs/fixtures/SG_TF_0006.violating.json new file mode 100644 index 00000000..900b2552 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0006.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_ami_launch_permission.test", + "mode": "managed", + "type": "aws_ami_launch_permission", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "id": "synthetic" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0007.compliant.json b/tests/packs/fixtures/SG_TF_0007.compliant.json new file mode 100644 index 00000000..34cb67b4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0007.compliant.json @@ -0,0 +1,57 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_lb.test", + "mode": "managed", + "type": "aws_lb", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "desync_mitigation_mode": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + }, + { + "address": "aws_alb.test", + "mode": "managed", + "type": "aws_alb", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "desync_mitigation_mode": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + }, + { + "address": "aws_elb.test", + "mode": "managed", + "type": "aws_elb", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "desync_mitigation_mode": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0007.violating.json b/tests/packs/fixtures/SG_TF_0007.violating.json new file mode 100644 index 00000000..aae6415d --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0007.violating.json @@ -0,0 +1,57 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_lb.test", + "mode": "managed", + "type": "aws_lb", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "desync_mitigation_mode": "monitor" + }, + "after_unknown": {} + } + }, + { + "address": "aws_alb.test", + "mode": "managed", + "type": "aws_alb", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "desync_mitigation_mode": "monitor" + }, + "after_unknown": {} + } + }, + { + "address": "aws_elb.test", + "mode": "managed", + "type": "aws_elb", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "desync_mitigation_mode": "monitor" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0008.compliant.json b/tests/packs/fixtures/SG_TF_0008.compliant.json new file mode 100644 index 00000000..433d9c0b --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0008.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_appsync_api_cache.test", + "mode": "managed", + "type": "aws_appsync_api_cache", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "transit_encryption_enabled": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0008.violating.json b/tests/packs/fixtures/SG_TF_0008.violating.json new file mode 100644 index 00000000..6e269142 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0008.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_appsync_api_cache.test", + "mode": "managed", + "type": "aws_appsync_api_cache", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "transit_encryption_enabled": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0009.compliant.json b/tests/packs/fixtures/SG_TF_0009.compliant.json new file mode 100644 index 00000000..10236345 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0009.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_appflow_flow.test", + "mode": "managed", + "type": "aws_appflow_flow", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_arn": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0009.violating.json b/tests/packs/fixtures/SG_TF_0009.violating.json new file mode 100644 index 00000000..218d6c9f --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0009.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_appflow_flow.test", + "mode": "managed", + "type": "aws_appflow_flow", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_arn": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0010.compliant.json b/tests/packs/fixtures/SG_TF_0010.compliant.json new file mode 100644 index 00000000..7f4edfaa --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0010.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_bedrockagent_agent.test", + "mode": "managed", + "type": "aws_bedrockagent_agent", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "guardrail_configuration": [ + { + "guardrail_identifier": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0010.violating.json b/tests/packs/fixtures/SG_TF_0010.violating.json new file mode 100644 index 00000000..d93c1649 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0010.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_bedrockagent_agent.test", + "mode": "managed", + "type": "aws_bedrockagent_agent", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "guardrail_configuration": [ + { + "guardrail_identifier": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0011.compliant.json b/tests/packs/fixtures/SG_TF_0011.compliant.json new file mode 100644 index 00000000..75ba94a1 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0011.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_athena_workgroup.test", + "mode": "managed", + "type": "aws_athena_workgroup", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [ + { + "enforce_workgroup_configuration": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0011.violating.json b/tests/packs/fixtures/SG_TF_0011.violating.json new file mode 100644 index 00000000..e7411e14 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0011.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_athena_workgroup.test", + "mode": "managed", + "type": "aws_athena_workgroup", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "configuration": [ + { + "enforce_workgroup_configuration": false + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0012.compliant.json b/tests/packs/fixtures/SG_TF_0012.compliant.json new file mode 100644 index 00000000..3cc373b7 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0012.compliant.json @@ -0,0 +1,31 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_codepipeline.test", + "mode": "managed", + "type": "aws_codepipeline", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "artifact_store": [ + { + "encryption_key": [ + { + "id": "tirith_corpus_sentinel" + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0012.violating.json b/tests/packs/fixtures/SG_TF_0012.violating.json new file mode 100644 index 00000000..05f4808a --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0012.violating.json @@ -0,0 +1,31 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_codepipeline.test", + "mode": "managed", + "type": "aws_codepipeline", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "artifact_store": [ + { + "encryption_key": [ + { + "id": null + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0013.compliant.json b/tests/packs/fixtures/SG_TF_0013.compliant.json new file mode 100644 index 00000000..7bc63ad3 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0013.compliant.json @@ -0,0 +1,31 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_codebuild_project.test", + "mode": "managed", + "type": "aws_codebuild_project", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "logs_config": [ + { + "s3_logs": [ + { + "encryption_disabled": false + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0013.violating.json b/tests/packs/fixtures/SG_TF_0013.violating.json new file mode 100644 index 00000000..5049fb09 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0013.violating.json @@ -0,0 +1,31 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_codebuild_project.test", + "mode": "managed", + "type": "aws_codebuild_project", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "logs_config": [ + { + "s3_logs": [ + { + "encryption_disabled": true + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0014.compliant.json b/tests/packs/fixtures/SG_TF_0014.compliant.json new file mode 100644 index 00000000..86f4a594 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0014.compliant.json @@ -0,0 +1,22 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_bucket.filler", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "filler", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "id": "filler" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0014.violating.json b/tests/packs/fixtures/SG_TF_0014.violating.json new file mode 100644 index 00000000..05e16195 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0014.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_default_vpc.test", + "mode": "managed", + "type": "aws_default_vpc", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "id": "synthetic" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0015.compliant.json b/tests/packs/fixtures/SG_TF_0015.compliant.json new file mode 100644 index 00000000..86f4a594 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0015.compliant.json @@ -0,0 +1,22 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_bucket.filler", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "filler", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "id": "filler" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0015.violating.json b/tests/packs/fixtures/SG_TF_0015.violating.json new file mode 100644 index 00000000..20740149 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0015.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_db_security_group.test", + "mode": "managed", + "type": "aws_db_security_group", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "id": "synthetic" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0016.compliant.json b/tests/packs/fixtures/SG_TF_0016.compliant.json new file mode 100644 index 00000000..774e98cb --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0016.compliant.json @@ -0,0 +1,40 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_db_instance.test", + "mode": "managed", + "type": "aws_db_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "auto_minor_version_upgrade": true + }, + "after_unknown": {} + } + }, + { + "address": "aws_rds_cluster_instance.test", + "mode": "managed", + "type": "aws_rds_cluster_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "auto_minor_version_upgrade": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0016.violating.json b/tests/packs/fixtures/SG_TF_0016.violating.json new file mode 100644 index 00000000..afc635f2 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0016.violating.json @@ -0,0 +1,40 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_db_instance.test", + "mode": "managed", + "type": "aws_db_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "auto_minor_version_upgrade": false + }, + "after_unknown": {} + } + }, + { + "address": "aws_rds_cluster_instance.test", + "mode": "managed", + "type": "aws_rds_cluster_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "auto_minor_version_upgrade": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0017.compliant.json b/tests/packs/fixtures/SG_TF_0017.compliant.json new file mode 100644 index 00000000..8a9160cf --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0017.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_dms_replication_instance.test", + "mode": "managed", + "type": "aws_dms_replication_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "publicly_accessible": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0017.violating.json b/tests/packs/fixtures/SG_TF_0017.violating.json new file mode 100644 index 00000000..00eeecd3 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0017.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_dms_replication_instance.test", + "mode": "managed", + "type": "aws_dms_replication_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "publicly_accessible": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0018.compliant.json b/tests/packs/fixtures/SG_TF_0018.compliant.json new file mode 100644 index 00000000..9ef5495b --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0018.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_ebs_snapshot_copy.test", + "mode": "managed", + "type": "aws_ebs_snapshot_copy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0018.violating.json b/tests/packs/fixtures/SG_TF_0018.violating.json new file mode 100644 index 00000000..7f9cddf9 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0018.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_ebs_snapshot_copy.test", + "mode": "managed", + "type": "aws_ebs_snapshot_copy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0019.compliant.json b/tests/packs/fixtures/SG_TF_0019.compliant.json new file mode 100644 index 00000000..01437f6f --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0019.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_ec2_transit_gateway.test", + "mode": "managed", + "type": "aws_ec2_transit_gateway", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "auto_accept_shared_attachments": "prefix-enable-suffix" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0019.violating.json b/tests/packs/fixtures/SG_TF_0019.violating.json new file mode 100644 index 00000000..45787397 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0019.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_ec2_transit_gateway.test", + "mode": "managed", + "type": "aws_ec2_transit_gateway", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "auto_accept_shared_attachments": "enable" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0020.compliant.json b/tests/packs/fixtures/SG_TF_0020.compliant.json new file mode 100644 index 00000000..86f4a594 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0020.compliant.json @@ -0,0 +1,22 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_bucket.filler", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "filler", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "id": "filler" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0020.violating.json b/tests/packs/fixtures/SG_TF_0020.violating.json new file mode 100644 index 00000000..091f83b0 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0020.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_elasticache_security_group.test", + "mode": "managed", + "type": "aws_elasticache_security_group", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "id": "synthetic" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0021.compliant.json b/tests/packs/fixtures/SG_TF_0021.compliant.json new file mode 100644 index 00000000..5d7864c4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0021.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_eks_cluster.test", + "mode": "managed", + "type": "aws_eks_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "version": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0021.violating.json b/tests/packs/fixtures/SG_TF_0021.violating.json new file mode 100644 index 00000000..9591b20a --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0021.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_eks_cluster.test", + "mode": "managed", + "type": "aws_eks_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "version": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0022.compliant.json b/tests/packs/fixtures/SG_TF_0022.compliant.json new file mode 100644 index 00000000..eb95bf83 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0022.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_elasticache_cluster.test", + "mode": "managed", + "type": "aws_elasticache_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "subnet_group_name": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0022.violating.json b/tests/packs/fixtures/SG_TF_0022.violating.json new file mode 100644 index 00000000..bf11402f --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0022.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_elasticache_cluster.test", + "mode": "managed", + "type": "aws_elasticache_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "subnet_group_name": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0023.compliant.json b/tests/packs/fixtures/SG_TF_0023.compliant.json new file mode 100644 index 00000000..801d2d3b --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0023.compliant.json @@ -0,0 +1,108 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_iam_policy.test", + "mode": "managed", + "type": "aws_iam_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "name": "prefix-IAMFullAccess-suffix" + }, + "after_unknown": {} + } + }, + { + "address": "aws_iam_policy_attachment.test", + "mode": "managed", + "type": "aws_iam_policy_attachment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy_arn": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + }, + { + "address": "aws_iam_user_policy_attachment.test", + "mode": "managed", + "type": "aws_iam_user_policy_attachment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy_arn": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + }, + { + "address": "aws_iam_role_policy_attachment.test", + "mode": "managed", + "type": "aws_iam_role_policy_attachment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy_arn": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + }, + { + "address": "aws_iam_group_policy_attachment.test", + "mode": "managed", + "type": "aws_iam_group_policy_attachment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy_arn": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + }, + { + "address": "aws_ssoadmin_managed_policy_attachment.test", + "mode": "managed", + "type": "aws_ssoadmin_managed_policy_attachment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "managed_policy_arn": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0023.violating.json b/tests/packs/fixtures/SG_TF_0023.violating.json new file mode 100644 index 00000000..378917af --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0023.violating.json @@ -0,0 +1,108 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_iam_policy.test", + "mode": "managed", + "type": "aws_iam_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "name": "IAMFullAccess" + }, + "after_unknown": {} + } + }, + { + "address": "aws_iam_policy_attachment.test", + "mode": "managed", + "type": "aws_iam_policy_attachment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy_arn": "arn:aws:iam::aws:policy/IAMFullAccess" + }, + "after_unknown": {} + } + }, + { + "address": "aws_iam_user_policy_attachment.test", + "mode": "managed", + "type": "aws_iam_user_policy_attachment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy_arn": "arn:aws:iam::aws:policy/IAMFullAccess" + }, + "after_unknown": {} + } + }, + { + "address": "aws_iam_role_policy_attachment.test", + "mode": "managed", + "type": "aws_iam_role_policy_attachment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy_arn": "arn:aws:iam::aws:policy/IAMFullAccess" + }, + "after_unknown": {} + } + }, + { + "address": "aws_iam_group_policy_attachment.test", + "mode": "managed", + "type": "aws_iam_group_policy_attachment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy_arn": "arn:aws:iam::aws:policy/IAMFullAccess" + }, + "after_unknown": {} + } + }, + { + "address": "aws_ssoadmin_managed_policy_attachment.test", + "mode": "managed", + "type": "aws_ssoadmin_managed_policy_attachment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "managed_policy_arn": "arn:aws:iam::aws:policy/IAMFullAccess" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0024.compliant.json b/tests/packs/fixtures/SG_TF_0024.compliant.json new file mode 100644 index 00000000..61a74117 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0024.compliant.json @@ -0,0 +1,57 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_glue_crawler.test", + "mode": "managed", + "type": "aws_glue_crawler", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "security_configuration": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + }, + { + "address": "aws_glue_dev_endpoint.test", + "mode": "managed", + "type": "aws_glue_dev_endpoint", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "security_configuration": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + }, + { + "address": "aws_glue_job.test", + "mode": "managed", + "type": "aws_glue_job", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "security_configuration": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0024.violating.json b/tests/packs/fixtures/SG_TF_0024.violating.json new file mode 100644 index 00000000..90e38885 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0024.violating.json @@ -0,0 +1,57 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_glue_crawler.test", + "mode": "managed", + "type": "aws_glue_crawler", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "security_configuration": null + }, + "after_unknown": {} + } + }, + { + "address": "aws_glue_dev_endpoint.test", + "mode": "managed", + "type": "aws_glue_dev_endpoint", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "security_configuration": null + }, + "after_unknown": {} + } + }, + { + "address": "aws_glue_job.test", + "mode": "managed", + "type": "aws_glue_job", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "security_configuration": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0025.compliant.json b/tests/packs/fixtures/SG_TF_0025.compliant.json new file mode 100644 index 00000000..86f4a594 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0025.compliant.json @@ -0,0 +1,22 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_bucket.filler", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "filler", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "id": "filler" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0025.violating.json b/tests/packs/fixtures/SG_TF_0025.violating.json new file mode 100644 index 00000000..92956daf --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0025.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_iam_user.test", + "mode": "managed", + "type": "aws_iam_user", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "id": "synthetic" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0026.compliant.json b/tests/packs/fixtures/SG_TF_0026.compliant.json new file mode 100644 index 00000000..ac546fc2 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0026.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_iam_access_key.test", + "mode": "managed", + "type": "aws_iam_access_key", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "user": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0026.violating.json b/tests/packs/fixtures/SG_TF_0026.violating.json new file mode 100644 index 00000000..c56a2dd9 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0026.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_iam_access_key.test", + "mode": "managed", + "type": "aws_iam_access_key", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "user": "root" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0027.compliant.json b/tests/packs/fixtures/SG_TF_0027.compliant.json new file mode 100644 index 00000000..8acff8a4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0027.compliant.json @@ -0,0 +1,69 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_instance.test", + "mode": "managed", + "type": "aws_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "metadata_options": [ + { + "http_tokens": "required" + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "aws_launch_template.test", + "mode": "managed", + "type": "aws_launch_template", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "metadata_options": [ + { + "http_tokens": "required" + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "aws_launch_configuration.test", + "mode": "managed", + "type": "aws_launch_configuration", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "metadata_options": [ + { + "http_tokens": "required" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0027.violating.json b/tests/packs/fixtures/SG_TF_0027.violating.json new file mode 100644 index 00000000..e7b472dc --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0027.violating.json @@ -0,0 +1,69 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_instance.test", + "mode": "managed", + "type": "aws_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "metadata_options": [ + { + "http_tokens": "prefix-required-suffix" + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "aws_launch_template.test", + "mode": "managed", + "type": "aws_launch_template", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "metadata_options": [ + { + "http_tokens": "prefix-required-suffix" + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "aws_launch_configuration.test", + "mode": "managed", + "type": "aws_launch_configuration", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "metadata_options": [ + { + "http_tokens": "prefix-required-suffix" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0028.compliant.json b/tests/packs/fixtures/SG_TF_0028.compliant.json new file mode 100644 index 00000000..442ed59a --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0028.compliant.json @@ -0,0 +1,58 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_instance.test", + "mode": "managed", + "type": "aws_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "root_block_device": [ + { + "encrypted": true + } + ], + "ebs_block_device": [ + { + "encrypted": true + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "aws_launch_configuration.test", + "mode": "managed", + "type": "aws_launch_configuration", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "root_block_device": [ + { + "encrypted": true + } + ], + "ebs_block_device": [ + { + "encrypted": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0028.violating.json b/tests/packs/fixtures/SG_TF_0028.violating.json new file mode 100644 index 00000000..26eb036c --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0028.violating.json @@ -0,0 +1,58 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_instance.test", + "mode": "managed", + "type": "aws_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "root_block_device": [ + { + "encrypted": false + } + ], + "ebs_block_device": [ + { + "encrypted": false + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "aws_launch_configuration.test", + "mode": "managed", + "type": "aws_launch_configuration", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "root_block_device": [ + { + "encrypted": false + } + ], + "ebs_block_device": [ + { + "encrypted": false + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0029.compliant.json b/tests/packs/fixtures/SG_TF_0029.compliant.json new file mode 100644 index 00000000..49ef49d8 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0029.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_kinesis_firehose_delivery_stream.test", + "mode": "managed", + "type": "aws_kinesis_firehose_delivery_stream", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "server_side_encryption": [ + { + "enabled": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0029.violating.json b/tests/packs/fixtures/SG_TF_0029.violating.json new file mode 100644 index 00000000..14bc1130 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0029.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_kinesis_firehose_delivery_stream.test", + "mode": "managed", + "type": "aws_kinesis_firehose_delivery_stream", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "server_side_encryption": [ + { + "enabled": false + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0030.compliant.json b/tests/packs/fixtures/SG_TF_0030.compliant.json new file mode 100644 index 00000000..b8b60754 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0030.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_kendra_index.test", + "mode": "managed", + "type": "aws_kendra_index", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "server_side_encryption_configuration": [ + { + "kms_key_id": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0030.violating.json b/tests/packs/fixtures/SG_TF_0030.violating.json new file mode 100644 index 00000000..59d561a5 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0030.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_kendra_index.test", + "mode": "managed", + "type": "aws_kendra_index", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "server_side_encryption_configuration": [ + { + "kms_key_id": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0031.compliant.json b/tests/packs/fixtures/SG_TF_0031.compliant.json new file mode 100644 index 00000000..28dd3698 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0031.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_memorydb_cluster.test", + "mode": "managed", + "type": "aws_memorydb_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_arn": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0031.violating.json b/tests/packs/fixtures/SG_TF_0031.violating.json new file mode 100644 index 00000000..30f1dcc4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0031.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_memorydb_cluster.test", + "mode": "managed", + "type": "aws_memorydb_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_arn": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0032.compliant.json b/tests/packs/fixtures/SG_TF_0032.compliant.json new file mode 100644 index 00000000..2585714b --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0032.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_lambda_permission.test", + "mode": "managed", + "type": "aws_lambda_permission", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "principal": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0032.violating.json b/tests/packs/fixtures/SG_TF_0032.violating.json new file mode 100644 index 00000000..8ffd3e8b --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0032.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_lambda_permission.test", + "mode": "managed", + "type": "aws_lambda_permission", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "principal": "*" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0033.compliant.json b/tests/packs/fixtures/SG_TF_0033.compliant.json new file mode 100644 index 00000000..27cc2c62 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0033.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_lambda_function.test", + "mode": "managed", + "type": "aws_lambda_function", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "runtime": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0033.violating.json b/tests/packs/fixtures/SG_TF_0033.violating.json new file mode 100644 index 00000000..601974de --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0033.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_lambda_function.test", + "mode": "managed", + "type": "aws_lambda_function", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "runtime": "dotnetcore3.1" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0034.compliant.json b/tests/packs/fixtures/SG_TF_0034.compliant.json new file mode 100644 index 00000000..6fa48bfe --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0034.compliant.json @@ -0,0 +1,31 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_mwaa_environment.test", + "mode": "managed", + "type": "aws_mwaa_environment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "logging_configuration": [ + { + "worker_logs": [ + { + "enabled": true + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0034.violating.json b/tests/packs/fixtures/SG_TF_0034.violating.json new file mode 100644 index 00000000..c2f2e064 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0034.violating.json @@ -0,0 +1,31 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_mwaa_environment.test", + "mode": "managed", + "type": "aws_mwaa_environment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "logging_configuration": [ + { + "worker_logs": [ + { + "enabled": false + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0035.compliant.json b/tests/packs/fixtures/SG_TF_0035.compliant.json new file mode 100644 index 00000000..13b95399 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0035.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_neptune_cluster.test", + "mode": "managed", + "type": "aws_neptune_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "backup_retention_period": 7 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0035.violating.json b/tests/packs/fixtures/SG_TF_0035.violating.json new file mode 100644 index 00000000..0df927f5 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0035.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_neptune_cluster.test", + "mode": "managed", + "type": "aws_neptune_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "backup_retention_period": 6 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0036.compliant.json b/tests/packs/fixtures/SG_TF_0036.compliant.json new file mode 100644 index 00000000..9531ebd3 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0036.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_redshift_cluster.test", + "mode": "managed", + "type": "aws_redshift_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "publicly_accessible": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0036.violating.json b/tests/packs/fixtures/SG_TF_0036.violating.json new file mode 100644 index 00000000..0a976a38 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0036.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_redshift_cluster.test", + "mode": "managed", + "type": "aws_redshift_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "publicly_accessible": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0037.compliant.json b/tests/packs/fixtures/SG_TF_0037.compliant.json new file mode 100644 index 00000000..7515ba85 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0037.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_bucket.test", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "object_lock_configuration": [ + { + "object_lock_enabled": "Enabled" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0037.violating.json b/tests/packs/fixtures/SG_TF_0037.violating.json new file mode 100644 index 00000000..48f6c2e5 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0037.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_bucket.test", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "object_lock_configuration": [ + { + "object_lock_enabled": "prefix-Enabled-suffix" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0038.compliant.json b/tests/packs/fixtures/SG_TF_0038.compliant.json new file mode 100644 index 00000000..01336522 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0038.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_object_copy.test", + "mode": "managed", + "type": "aws_s3_object_copy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0038.violating.json b/tests/packs/fixtures/SG_TF_0038.violating.json new file mode 100644 index 00000000..9ce0af1f --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0038.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_object_copy.test", + "mode": "managed", + "type": "aws_s3_object_copy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0039.compliant.json b/tests/packs/fixtures/SG_TF_0039.compliant.json new file mode 100644 index 00000000..a70d159f --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0039.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_bucket_object.test", + "mode": "managed", + "type": "aws_s3_bucket_object", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0039.violating.json b/tests/packs/fixtures/SG_TF_0039.violating.json new file mode 100644 index 00000000..ef794735 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0039.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_s3_bucket_object.test", + "mode": "managed", + "type": "aws_s3_bucket_object", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_id": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0040.compliant.json b/tests/packs/fixtures/SG_TF_0040.compliant.json new file mode 100644 index 00000000..5f528c00 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0040.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_sagemaker_notebook_instance.test", + "mode": "managed", + "type": "aws_sagemaker_notebook_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "root_access": "Disabled" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0040.violating.json b/tests/packs/fixtures/SG_TF_0040.violating.json new file mode 100644 index 00000000..4887ecf5 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0040.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_sagemaker_notebook_instance.test", + "mode": "managed", + "type": "aws_sagemaker_notebook_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "root_access": "prefix-Disabled-suffix" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0041.compliant.json b/tests/packs/fixtures/SG_TF_0041.compliant.json new file mode 100644 index 00000000..706e75fc --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0041.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_sagemaker_data_quality_job_definition.test", + "mode": "managed", + "type": "aws_sagemaker_data_quality_job_definition", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "data_quality_job_output_config": [ + { + "kms_key_id": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0041.violating.json b/tests/packs/fixtures/SG_TF_0041.violating.json new file mode 100644 index 00000000..b1864dfe --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0041.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_sagemaker_data_quality_job_definition.test", + "mode": "managed", + "type": "aws_sagemaker_data_quality_job_definition", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "data_quality_job_output_config": [ + { + "kms_key_id": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0042.compliant.json b/tests/packs/fixtures/SG_TF_0042.compliant.json new file mode 100644 index 00000000..bd54edf3 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0042.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_sagemaker_notebook_instance.test", + "mode": "managed", + "type": "aws_sagemaker_notebook_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "instance_metadata_service_configuration": [ + { + "minimum_instance_metadata_service_version": "2" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0042.violating.json b/tests/packs/fixtures/SG_TF_0042.violating.json new file mode 100644 index 00000000..ee464c78 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0042.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_sagemaker_notebook_instance.test", + "mode": "managed", + "type": "aws_sagemaker_notebook_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "instance_metadata_service_configuration": [ + { + "minimum_instance_metadata_service_version": "prefix-2-suffix" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0043.compliant.json b/tests/packs/fixtures/SG_TF_0043.compliant.json new file mode 100644 index 00000000..2d8078de --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0043.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_sns_topic.test", + "mode": "managed", + "type": "aws_sns_topic", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_master_key_id": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0043.violating.json b/tests/packs/fixtures/SG_TF_0043.violating.json new file mode 100644 index 00000000..5e01bff8 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0043.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_sns_topic.test", + "mode": "managed", + "type": "aws_sns_topic", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_master_key_id": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0044.compliant.json b/tests/packs/fixtures/SG_TF_0044.compliant.json new file mode 100644 index 00000000..c9f0979e --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0044.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_ses_configuration_set.test", + "mode": "managed", + "type": "aws_ses_configuration_set", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "delivery_options": [ + { + "tls_policy": "Require" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0044.violating.json b/tests/packs/fixtures/SG_TF_0044.violating.json new file mode 100644 index 00000000..e8ab0d0c --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0044.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_ses_configuration_set.test", + "mode": "managed", + "type": "aws_ses_configuration_set", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "delivery_options": [ + { + "tls_policy": "prefix-Require-suffix" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0045.compliant.json b/tests/packs/fixtures/SG_TF_0045.compliant.json new file mode 100644 index 00000000..2c91d852 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0045.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_sagemaker_endpoint_configuration.test", + "mode": "managed", + "type": "aws_sagemaker_endpoint_configuration", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_arn": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0045.violating.json b/tests/packs/fixtures/SG_TF_0045.violating.json new file mode 100644 index 00000000..815ccac1 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0045.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_sagemaker_endpoint_configuration.test", + "mode": "managed", + "type": "aws_sagemaker_endpoint_configuration", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_arn": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0046.compliant.json b/tests/packs/fixtures/SG_TF_0046.compliant.json new file mode 100644 index 00000000..dd58cca8 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0046.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_workspaces_workspace.test", + "mode": "managed", + "type": "aws_workspaces_workspace", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "root_volume_encryption_enabled": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0046.violating.json b/tests/packs/fixtures/SG_TF_0046.violating.json new file mode 100644 index 00000000..6f0f87b8 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0046.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "aws_workspaces_workspace.test", + "mode": "managed", + "type": "aws_workspaces_workspace", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "root_volume_encryption_enabled": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0047.compliant.json b/tests/packs/fixtures/SG_TF_0047.compliant.json new file mode 100644 index 00000000..d04460ed --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0047.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_automation_account.test", + "mode": "managed", + "type": "azurerm_automation_account", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "public_network_access_enabled": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0047.violating.json b/tests/packs/fixtures/SG_TF_0047.violating.json new file mode 100644 index 00000000..507692a2 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0047.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_automation_account.test", + "mode": "managed", + "type": "azurerm_automation_account", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "public_network_access_enabled": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0048.compliant.json b/tests/packs/fixtures/SG_TF_0048.compliant.json new file mode 100644 index 00000000..3c102d41 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0048.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_automation_account.test", + "mode": "managed", + "type": "azurerm_automation_account", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "identity": [ + { + "type": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0048.violating.json b/tests/packs/fixtures/SG_TF_0048.violating.json new file mode 100644 index 00000000..36b9dc09 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0048.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_automation_account.test", + "mode": "managed", + "type": "azurerm_automation_account", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "identity": [ + { + "type": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0049.compliant.json b/tests/packs/fixtures/SG_TF_0049.compliant.json new file mode 100644 index 00000000..a8c69657 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0049.compliant.json @@ -0,0 +1,31 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_api_management.test", + "mode": "managed", + "type": "azurerm_api_management", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "security": [ + { + "enable_backend_ssl30": false, + "enable_backend_tls10": false, + "enable_frontend_ssl30": false, + "enable_frontend_tls10": false, + "enable_frontend_tls11": false + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0049.violating.json b/tests/packs/fixtures/SG_TF_0049.violating.json new file mode 100644 index 00000000..a697535c --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0049.violating.json @@ -0,0 +1,31 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_api_management.test", + "mode": "managed", + "type": "azurerm_api_management", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "security": [ + { + "enable_backend_ssl30": true, + "enable_backend_tls10": true, + "enable_frontend_ssl30": true, + "enable_frontend_tls10": true, + "enable_frontend_tls11": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0050.compliant.json b/tests/packs/fixtures/SG_TF_0050.compliant.json new file mode 100644 index 00000000..fd66d4b4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0050.compliant.json @@ -0,0 +1,81 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_app_service.test", + "mode": "managed", + "type": "azurerm_app_service", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "site_config": [ + { + "cors": [ + { + "allowed_origins": "*" + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "azurerm_linux_web_app.test", + "mode": "managed", + "type": "azurerm_linux_web_app", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "site_config": [ + { + "cors": [ + { + "allowed_origins": "*" + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "azurerm_windows_web_app.test", + "mode": "managed", + "type": "azurerm_windows_web_app", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "site_config": [ + { + "cors": [ + { + "allowed_origins": "*" + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0050.violating.json b/tests/packs/fixtures/SG_TF_0050.violating.json new file mode 100644 index 00000000..5405777e --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0050.violating.json @@ -0,0 +1,87 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_app_service.test", + "mode": "managed", + "type": "azurerm_app_service", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "site_config": [ + { + "cors": [ + { + "allowed_origins": [ + "*" + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "azurerm_linux_web_app.test", + "mode": "managed", + "type": "azurerm_linux_web_app", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "site_config": [ + { + "cors": [ + { + "allowed_origins": [ + "*" + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "azurerm_windows_web_app.test", + "mode": "managed", + "type": "azurerm_windows_web_app", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "site_config": [ + { + "cors": [ + { + "allowed_origins": [ + "*" + ] + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0051.compliant.json b/tests/packs/fixtures/SG_TF_0051.compliant.json new file mode 100644 index 00000000..e54a53ce --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0051.compliant.json @@ -0,0 +1,69 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_app_service.test", + "mode": "managed", + "type": "azurerm_app_service", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "storage_account": [ + { + "type": "AzureFiles" + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "azurerm_linux_web_app.test", + "mode": "managed", + "type": "azurerm_linux_web_app", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "storage_account": [ + { + "type": "AzureFiles" + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "azurerm_windows_web_app.test", + "mode": "managed", + "type": "azurerm_windows_web_app", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "storage_account": [ + { + "type": "AzureFiles" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0051.violating.json b/tests/packs/fixtures/SG_TF_0051.violating.json new file mode 100644 index 00000000..a1a5955e --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0051.violating.json @@ -0,0 +1,69 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_app_service.test", + "mode": "managed", + "type": "azurerm_app_service", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "storage_account": [ + { + "type": "prefix-AzureFiles-suffix" + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "azurerm_linux_web_app.test", + "mode": "managed", + "type": "azurerm_linux_web_app", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "storage_account": [ + { + "type": "prefix-AzureFiles-suffix" + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "azurerm_windows_web_app.test", + "mode": "managed", + "type": "azurerm_windows_web_app", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "storage_account": [ + { + "type": "prefix-AzureFiles-suffix" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0052.compliant.json b/tests/packs/fixtures/SG_TF_0052.compliant.json new file mode 100644 index 00000000..cfa10dc5 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0052.compliant.json @@ -0,0 +1,24 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_container_registry.test", + "mode": "managed", + "type": "azurerm_container_registry", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "sku": "Premium", + "georeplications": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0052.violating.json b/tests/packs/fixtures/SG_TF_0052.violating.json new file mode 100644 index 00000000..af2c3e8f --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0052.violating.json @@ -0,0 +1,24 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_container_registry.test", + "mode": "managed", + "type": "azurerm_container_registry", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "sku": "prefix-Premium-suffix", + "georeplications": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0053.compliant.json b/tests/packs/fixtures/SG_TF_0053.compliant.json new file mode 100644 index 00000000..f62f6dfe --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0053.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_container_registry.test", + "mode": "managed", + "type": "azurerm_container_registry", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "quarantine_policy_enabled": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0053.violating.json b/tests/packs/fixtures/SG_TF_0053.violating.json new file mode 100644 index 00000000..e0ef2b6d --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0053.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_container_registry.test", + "mode": "managed", + "type": "azurerm_container_registry", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "quarantine_policy_enabled": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0054.compliant.json b/tests/packs/fixtures/SG_TF_0054.compliant.json new file mode 100644 index 00000000..71e3a0a9 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0054.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_data_factory.test", + "mode": "managed", + "type": "azurerm_data_factory", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "public_network_enabled": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0054.violating.json b/tests/packs/fixtures/SG_TF_0054.violating.json new file mode 100644 index 00000000..c6b1b9bc --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0054.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_data_factory.test", + "mode": "managed", + "type": "azurerm_data_factory", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "public_network_enabled": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0055.compliant.json b/tests/packs/fixtures/SG_TF_0055.compliant.json new file mode 100644 index 00000000..a6c282f9 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0055.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_container_group.test", + "mode": "managed", + "type": "azurerm_container_group", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "subnet_ids": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0055.violating.json b/tests/packs/fixtures/SG_TF_0055.violating.json new file mode 100644 index 00000000..8aab2a48 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0055.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_container_group.test", + "mode": "managed", + "type": "azurerm_container_group", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "subnet_ids": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0056.compliant.json b/tests/packs/fixtures/SG_TF_0056.compliant.json new file mode 100644 index 00000000..7bed8ec4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0056.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_frontdoor.test", + "mode": "managed", + "type": "azurerm_frontdoor", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "frontend_endpoint": [ + { + "web_application_firewall_policy_link_id": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0056.violating.json b/tests/packs/fixtures/SG_TF_0056.violating.json new file mode 100644 index 00000000..a131f736 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0056.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_frontdoor.test", + "mode": "managed", + "type": "azurerm_frontdoor", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "frontend_endpoint": [ + { + "web_application_firewall_policy_link_id": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0057.compliant.json b/tests/packs/fixtures/SG_TF_0057.compliant.json new file mode 100644 index 00000000..f654ecef --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0057.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_eventgrid_topic.test", + "mode": "managed", + "type": "azurerm_eventgrid_topic", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "identity": [ + { + "type": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0057.violating.json b/tests/packs/fixtures/SG_TF_0057.violating.json new file mode 100644 index 00000000..ce9dd141 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0057.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_eventgrid_topic.test", + "mode": "managed", + "type": "azurerm_eventgrid_topic", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "identity": [ + { + "type": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0058.compliant.json b/tests/packs/fixtures/SG_TF_0058.compliant.json new file mode 100644 index 00000000..01a6a14e --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0058.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_eventhub_namespace.test", + "mode": "managed", + "type": "azurerm_eventhub_namespace", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "location": "Australia East" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0058.violating.json b/tests/packs/fixtures/SG_TF_0058.violating.json new file mode 100644 index 00000000..f3be9f69 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0058.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_eventhub_namespace.test", + "mode": "managed", + "type": "azurerm_eventhub_namespace", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "location": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0059.compliant.json b/tests/packs/fixtures/SG_TF_0059.compliant.json new file mode 100644 index 00000000..da4a1582 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0059.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_iothub.test", + "mode": "managed", + "type": "azurerm_iothub", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "public_network_access_enabled": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0059.violating.json b/tests/packs/fixtures/SG_TF_0059.violating.json new file mode 100644 index 00000000..6c8b75ed --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0059.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_iothub.test", + "mode": "managed", + "type": "azurerm_iothub", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "public_network_access_enabled": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0060.compliant.json b/tests/packs/fixtures/SG_TF_0060.compliant.json new file mode 100644 index 00000000..94a7778e --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0060.compliant.json @@ -0,0 +1,44 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_kubernetes_cluster.test", + "mode": "managed", + "type": "azurerm_kubernetes_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "default_node_pool": [ + { + "max_pods": 50 + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "azurerm_kubernetes_cluster_node_pool.test", + "mode": "managed", + "type": "azurerm_kubernetes_cluster_node_pool", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "max_pods": 50 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0060.violating.json b/tests/packs/fixtures/SG_TF_0060.violating.json new file mode 100644 index 00000000..c4da5ab1 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0060.violating.json @@ -0,0 +1,44 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_kubernetes_cluster.test", + "mode": "managed", + "type": "azurerm_kubernetes_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "default_node_pool": [ + { + "max_pods": 49 + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "azurerm_kubernetes_cluster_node_pool.test", + "mode": "managed", + "type": "azurerm_kubernetes_cluster_node_pool", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "max_pods": 49 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0061.compliant.json b/tests/packs/fixtures/SG_TF_0061.compliant.json new file mode 100644 index 00000000..c47f0510 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0061.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_kusto_cluster.test", + "mode": "managed", + "type": "azurerm_kusto_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "identity": [ + { + "type": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0061.violating.json b/tests/packs/fixtures/SG_TF_0061.violating.json new file mode 100644 index 00000000..70c5bdde --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0061.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_kusto_cluster.test", + "mode": "managed", + "type": "azurerm_kusto_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "identity": [ + { + "type": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0062.compliant.json b/tests/packs/fixtures/SG_TF_0062.compliant.json new file mode 100644 index 00000000..e8ac6eab --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0062.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_monitor_log_profile.test", + "mode": "managed", + "type": "azurerm_monitor_log_profile", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "categories": [ + "Write", + "Delete", + "Action" + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0062.violating.json b/tests/packs/fixtures/SG_TF_0062.violating.json new file mode 100644 index 00000000..b19493cc --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0062.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_monitor_log_profile.test", + "mode": "managed", + "type": "azurerm_monitor_log_profile", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "categories": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0063.compliant.json b/tests/packs/fixtures/SG_TF_0063.compliant.json new file mode 100644 index 00000000..f6c7e980 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0063.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_network_interface.test", + "mode": "managed", + "type": "azurerm_network_interface", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "enable_ip_forwarding": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0063.violating.json b/tests/packs/fixtures/SG_TF_0063.violating.json new file mode 100644 index 00000000..bcf39227 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0063.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_network_interface.test", + "mode": "managed", + "type": "azurerm_network_interface", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "enable_ip_forwarding": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0064.compliant.json b/tests/packs/fixtures/SG_TF_0064.compliant.json new file mode 100644 index 00000000..dda7ff85 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0064.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_search_service.test", + "mode": "managed", + "type": "azurerm_search_service", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "public_network_access_enabled": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0064.violating.json b/tests/packs/fixtures/SG_TF_0064.violating.json new file mode 100644 index 00000000..fec685ad --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0064.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_search_service.test", + "mode": "managed", + "type": "azurerm_search_service", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "public_network_access_enabled": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0065.compliant.json b/tests/packs/fixtures/SG_TF_0065.compliant.json new file mode 100644 index 00000000..75ec1f62 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0065.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_search_service.test", + "mode": "managed", + "type": "azurerm_search_service", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "replica_count": 2 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0065.violating.json b/tests/packs/fixtures/SG_TF_0065.violating.json new file mode 100644 index 00000000..7c28f621 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0065.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_search_service.test", + "mode": "managed", + "type": "azurerm_search_service", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "replica_count": 1 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0066.compliant.json b/tests/packs/fixtures/SG_TF_0066.compliant.json new file mode 100644 index 00000000..d58f709d --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0066.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_service_fabric_cluster.test", + "mode": "managed", + "type": "azurerm_service_fabric_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "azure_active_directory": [ + { + "tenant_id": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0066.violating.json b/tests/packs/fixtures/SG_TF_0066.violating.json new file mode 100644 index 00000000..f2c23b0f --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0066.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_service_fabric_cluster.test", + "mode": "managed", + "type": "azurerm_service_fabric_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "azure_active_directory": [ + { + "tenant_id": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0067.compliant.json b/tests/packs/fixtures/SG_TF_0067.compliant.json new file mode 100644 index 00000000..575b6845 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0067.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_service_plan.test", + "mode": "managed", + "type": "azurerm_service_plan", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "worker_count": 2 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0067.violating.json b/tests/packs/fixtures/SG_TF_0067.violating.json new file mode 100644 index 00000000..bdda073c --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0067.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_service_plan.test", + "mode": "managed", + "type": "azurerm_service_plan", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "worker_count": 1 + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0068.compliant.json b/tests/packs/fixtures/SG_TF_0068.compliant.json new file mode 100644 index 00000000..f4c64d93 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0068.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_service_plan.test", + "mode": "managed", + "type": "azurerm_service_plan", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "zone_balancing_enabled": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0068.violating.json b/tests/packs/fixtures/SG_TF_0068.violating.json new file mode 100644 index 00000000..b16c0898 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0068.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_service_plan.test", + "mode": "managed", + "type": "azurerm_service_plan", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "zone_balancing_enabled": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0069.compliant.json b/tests/packs/fixtures/SG_TF_0069.compliant.json new file mode 100644 index 00000000..96544b0e --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0069.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_security_center_contact.test", + "mode": "managed", + "type": "azurerm_security_center_contact", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "alerts_to_admins": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0069.violating.json b/tests/packs/fixtures/SG_TF_0069.violating.json new file mode 100644 index 00000000..79b53cb0 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0069.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_security_center_contact.test", + "mode": "managed", + "type": "azurerm_security_center_contact", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "alerts_to_admins": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0070.compliant.json b/tests/packs/fixtures/SG_TF_0070.compliant.json new file mode 100644 index 00000000..84a6d179 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0070.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_servicebus_namespace.test", + "mode": "managed", + "type": "azurerm_servicebus_namespace", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "customer_managed_key": [ + { + "infrastructure_encryption_enabled": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0070.violating.json b/tests/packs/fixtures/SG_TF_0070.violating.json new file mode 100644 index 00000000..01242730 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0070.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_servicebus_namespace.test", + "mode": "managed", + "type": "azurerm_servicebus_namespace", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "customer_managed_key": [ + { + "infrastructure_encryption_enabled": false + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0071.compliant.json b/tests/packs/fixtures/SG_TF_0071.compliant.json new file mode 100644 index 00000000..31c1f9b8 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0071.compliant.json @@ -0,0 +1,28 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_virtual_machine.test", + "mode": "managed", + "type": "azurerm_virtual_machine", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "storage_os_disk": [ + { + "managed_disk_type": "tirith_corpus_sentinel", + "vhd_uri": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0071.violating.json b/tests/packs/fixtures/SG_TF_0071.violating.json new file mode 100644 index 00000000..b20351f8 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0071.violating.json @@ -0,0 +1,28 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_virtual_machine.test", + "mode": "managed", + "type": "azurerm_virtual_machine", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "storage_os_disk": [ + { + "managed_disk_type": null, + "vhd_uri": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0072.compliant.json b/tests/packs/fixtures/SG_TF_0072.compliant.json new file mode 100644 index 00000000..3f173659 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0072.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_web_application_firewall_policy.test", + "mode": "managed", + "type": "azurerm_web_application_firewall_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy_settings": [ + { + "enabled": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0072.violating.json b/tests/packs/fixtures/SG_TF_0072.violating.json new file mode 100644 index 00000000..862a9385 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0072.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "azurerm_web_application_firewall_policy.test", + "mode": "managed", + "type": "azurerm_web_application_firewall_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy_settings": [ + { + "enabled": false + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0073.compliant.json b/tests/packs/fixtures/SG_TF_0073.compliant.json new file mode 100644 index 00000000..c177c71e --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0073.compliant.json @@ -0,0 +1,29 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "digitalocean_firewall.test", + "mode": "managed", + "type": "digitalocean_firewall", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "inbound_rule": [ + { + "source_addresses": [ + "tirith_corpus_sentinel" + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0073.violating.json b/tests/packs/fixtures/SG_TF_0073.violating.json new file mode 100644 index 00000000..b98eb599 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0073.violating.json @@ -0,0 +1,29 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "digitalocean_firewall.test", + "mode": "managed", + "type": "digitalocean_firewall", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "inbound_rule": [ + { + "source_addresses": [ + "0.0.0.0/0" + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0074.compliant.json b/tests/packs/fixtures/SG_TF_0074.compliant.json new file mode 100644 index 00000000..938f83a4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0074.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_bigquery_table.test", + "mode": "managed", + "type": "google_bigquery_table", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "deletion_protection": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0074.violating.json b/tests/packs/fixtures/SG_TF_0074.violating.json new file mode 100644 index 00000000..d2774bc0 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0074.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_bigquery_table.test", + "mode": "managed", + "type": "google_bigquery_table", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "deletion_protection": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0075.compliant.json b/tests/packs/fixtures/SG_TF_0075.compliant.json new file mode 100644 index 00000000..534742fe --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0075.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_bigquery_table.test", + "mode": "managed", + "type": "google_bigquery_table", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "encryption_configuration": [ + { + "kms_key_name": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0075.violating.json b/tests/packs/fixtures/SG_TF_0075.violating.json new file mode 100644 index 00000000..0676df3b --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0075.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_bigquery_table.test", + "mode": "managed", + "type": "google_bigquery_table", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "encryption_configuration": [ + { + "kms_key_name": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0076.compliant.json b/tests/packs/fixtures/SG_TF_0076.compliant.json new file mode 100644 index 00000000..fb5912e3 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0076.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_artifact_registry_repository.test", + "mode": "managed", + "type": "google_artifact_registry_repository", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_name": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0076.violating.json b/tests/packs/fixtures/SG_TF_0076.violating.json new file mode 100644 index 00000000..2f312634 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0076.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_artifact_registry_repository.test", + "mode": "managed", + "type": "google_artifact_registry_repository", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key_name": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0077.compliant.json b/tests/packs/fixtures/SG_TF_0077.compliant.json new file mode 100644 index 00000000..a9785011 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0077.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_compute_disk.test", + "mode": "managed", + "type": "google_compute_disk", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "disk_encryption_key": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0077.violating.json b/tests/packs/fixtures/SG_TF_0077.violating.json new file mode 100644 index 00000000..2e80f21a --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0077.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_compute_disk.test", + "mode": "managed", + "type": "google_compute_disk", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "disk_encryption_key": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0078.compliant.json b/tests/packs/fixtures/SG_TF_0078.compliant.json new file mode 100644 index 00000000..218c39dc --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0078.compliant.json @@ -0,0 +1,72 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_compute_instance.test", + "mode": "managed", + "type": "google_compute_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "shielded_instance_config": [ + { + "enable_vtpm": true, + "enable_integrity_monitoring": true + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "google_compute_instance_template.test", + "mode": "managed", + "type": "google_compute_instance_template", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "shielded_instance_config": [ + { + "enable_vtpm": true, + "enable_integrity_monitoring": true + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "google_compute_instance_from_template.test", + "mode": "managed", + "type": "google_compute_instance_from_template", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "shielded_instance_config": [ + { + "enable_vtpm": true, + "enable_integrity_monitoring": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0078.violating.json b/tests/packs/fixtures/SG_TF_0078.violating.json new file mode 100644 index 00000000..da826722 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0078.violating.json @@ -0,0 +1,72 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_compute_instance.test", + "mode": "managed", + "type": "google_compute_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "shielded_instance_config": [ + { + "enable_vtpm": false, + "enable_integrity_monitoring": true + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "google_compute_instance_template.test", + "mode": "managed", + "type": "google_compute_instance_template", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "shielded_instance_config": [ + { + "enable_vtpm": true, + "enable_integrity_monitoring": true + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "google_compute_instance_from_template.test", + "mode": "managed", + "type": "google_compute_instance_from_template", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "shielded_instance_config": [ + { + "enable_vtpm": true, + "enable_integrity_monitoring": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0079.compliant.json b/tests/packs/fixtures/SG_TF_0079.compliant.json new file mode 100644 index 00000000..98c0c641 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0079.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_container_cluster.test", + "mode": "managed", + "type": "google_container_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "logging_service": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0079.violating.json b/tests/packs/fixtures/SG_TF_0079.violating.json new file mode 100644 index 00000000..a8ae4d63 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0079.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_container_cluster.test", + "mode": "managed", + "type": "google_container_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "logging_service": "none" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0080.compliant.json b/tests/packs/fixtures/SG_TF_0080.compliant.json new file mode 100644 index 00000000..1712dea0 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0080.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_container_cluster.test", + "mode": "managed", + "type": "google_container_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "private_cluster_config": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0080.violating.json b/tests/packs/fixtures/SG_TF_0080.violating.json new file mode 100644 index 00000000..bbbb10c1 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0080.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_container_cluster.test", + "mode": "managed", + "type": "google_container_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "private_cluster_config": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0081.compliant.json b/tests/packs/fixtures/SG_TF_0081.compliant.json new file mode 100644 index 00000000..3849dd46 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0081.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_document_ai_warehouse_location.test", + "mode": "managed", + "type": "google_document_ai_warehouse_location", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0081.violating.json b/tests/packs/fixtures/SG_TF_0081.violating.json new file mode 100644 index 00000000..3a964645 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0081.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_document_ai_warehouse_location.test", + "mode": "managed", + "type": "google_document_ai_warehouse_location", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0082.compliant.json b/tests/packs/fixtures/SG_TF_0082.compliant.json new file mode 100644 index 00000000..aa04d3c9 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0082.compliant.json @@ -0,0 +1,24 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_notebooks_instance.test", + "mode": "managed", + "type": "google_notebooks_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key": "tirith_corpus_sentinel", + "disk_encryption": "CMEK" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0082.violating.json b/tests/packs/fixtures/SG_TF_0082.violating.json new file mode 100644 index 00000000..57169ac4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0082.violating.json @@ -0,0 +1,24 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_notebooks_instance.test", + "mode": "managed", + "type": "google_notebooks_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "kms_key": null, + "disk_encryption": "prefix-CMEK-suffix" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0083.compliant.json b/tests/packs/fixtures/SG_TF_0083.compliant.json new file mode 100644 index 00000000..226caddc --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0083.compliant.json @@ -0,0 +1,40 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_kms_crypto_key_iam_member.test", + "mode": "managed", + "type": "google_kms_crypto_key_iam_member", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "member": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + }, + { + "address": "google_kms_crypto_key_iam_binding.test", + "mode": "managed", + "type": "google_kms_crypto_key_iam_binding", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "members": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0083.violating.json b/tests/packs/fixtures/SG_TF_0083.violating.json new file mode 100644 index 00000000..781d6e66 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0083.violating.json @@ -0,0 +1,43 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_kms_crypto_key_iam_member.test", + "mode": "managed", + "type": "google_kms_crypto_key_iam_member", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "member": "allUsers" + }, + "after_unknown": {} + } + }, + { + "address": "google_kms_crypto_key_iam_binding.test", + "mode": "managed", + "type": "google_kms_crypto_key_iam_binding", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "members": [ + "allUsers", + "allAuthenticatedUsers" + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0084.compliant.json b/tests/packs/fixtures/SG_TF_0084.compliant.json new file mode 100644 index 00000000..0df242e4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0084.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_notebooks_instance.test", + "mode": "managed", + "type": "google_notebooks_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "no_public_ip": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0084.violating.json b/tests/packs/fixtures/SG_TF_0084.violating.json new file mode 100644 index 00000000..cbf978ef --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0084.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_notebooks_instance.test", + "mode": "managed", + "type": "google_notebooks_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "no_public_ip": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0085.compliant.json b/tests/packs/fixtures/SG_TF_0085.compliant.json new file mode 100644 index 00000000..672785bd --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0085.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_spanner_database.test", + "mode": "managed", + "type": "google_spanner_database", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "enable_drop_protection": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0085.violating.json b/tests/packs/fixtures/SG_TF_0085.violating.json new file mode 100644 index 00000000..cc324d70 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0085.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_spanner_database.test", + "mode": "managed", + "type": "google_spanner_database", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "enable_drop_protection": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0086.compliant.json b/tests/packs/fixtures/SG_TF_0086.compliant.json new file mode 100644 index 00000000..8bd1bb96 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0086.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_spanner_database.test", + "mode": "managed", + "type": "google_spanner_database", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "encryption_config": [ + { + "kms_key_name": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0086.violating.json b/tests/packs/fixtures/SG_TF_0086.violating.json new file mode 100644 index 00000000..16fafd05 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0086.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_spanner_database.test", + "mode": "managed", + "type": "google_spanner_database", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "encryption_config": [ + { + "kms_key_name": null + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0087.compliant.json b/tests/packs/fixtures/SG_TF_0087.compliant.json new file mode 100644 index 00000000..2a841c53 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0087.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_storage_bucket.test", + "mode": "managed", + "type": "google_storage_bucket", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "public_access_prevention": "enforced" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0087.violating.json b/tests/packs/fixtures/SG_TF_0087.violating.json new file mode 100644 index 00000000..619354cf --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0087.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_storage_bucket.test", + "mode": "managed", + "type": "google_storage_bucket", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "public_access_prevention": "prefix-enforced-suffix" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0088.compliant.json b/tests/packs/fixtures/SG_TF_0088.compliant.json new file mode 100644 index 00000000..5e36b51a --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0088.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_storage_bucket.test", + "mode": "managed", + "type": "google_storage_bucket", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "versioning": [ + { + "enabled": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0088.violating.json b/tests/packs/fixtures/SG_TF_0088.violating.json new file mode 100644 index 00000000..13ee4c36 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0088.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "google_storage_bucket.test", + "mode": "managed", + "type": "google_storage_bucket", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "versioning": [ + { + "enabled": false + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0089.compliant.json b/tests/packs/fixtures/SG_TF_0089.compliant.json new file mode 100644 index 00000000..0f6bfb64 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0089.compliant.json @@ -0,0 +1,138 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "kubernetes_pod.test", + "mode": "managed", + "type": "kubernetes_pod", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "env": [ + { + "name": "prefix-GITSYNC_GIT-suffix" + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_pod_v1.test", + "mode": "managed", + "type": "kubernetes_pod_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "env": [ + { + "name": "prefix-GITSYNC_GIT-suffix" + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment.test", + "mode": "managed", + "type": "kubernetes_deployment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "env": [ + { + "name": "prefix-GITSYNC_GIT-suffix" + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment_v1.test", + "mode": "managed", + "type": "kubernetes_deployment_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "env": [ + { + "name": "prefix-GITSYNC_GIT-suffix" + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0089.violating.json b/tests/packs/fixtures/SG_TF_0089.violating.json new file mode 100644 index 00000000..d9e64ddc --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0089.violating.json @@ -0,0 +1,138 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "kubernetes_pod.test", + "mode": "managed", + "type": "kubernetes_pod", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "env": [ + { + "name": "GITSYNC_GIT" + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_pod_v1.test", + "mode": "managed", + "type": "kubernetes_pod_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "env": [ + { + "name": "GITSYNC_GIT" + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment.test", + "mode": "managed", + "type": "kubernetes_deployment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "env": [ + { + "name": "GITSYNC_GIT" + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment_v1.test", + "mode": "managed", + "type": "kubernetes_deployment_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "env": [ + { + "name": "GITSYNC_GIT" + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0090.compliant.json b/tests/packs/fixtures/SG_TF_0090.compliant.json new file mode 100644 index 00000000..047d862c --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0090.compliant.json @@ -0,0 +1,122 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "kubernetes_pod.test", + "mode": "managed", + "type": "kubernetes_pod", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "image_pull_policy": "Always" + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_pod_v1.test", + "mode": "managed", + "type": "kubernetes_pod_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "image_pull_policy": "Always" + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment.test", + "mode": "managed", + "type": "kubernetes_deployment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "image_pull_policy": "Always" + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment_v1.test", + "mode": "managed", + "type": "kubernetes_deployment_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "image_pull_policy": "Always" + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0090.violating.json b/tests/packs/fixtures/SG_TF_0090.violating.json new file mode 100644 index 00000000..407d6f70 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0090.violating.json @@ -0,0 +1,122 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "kubernetes_pod.test", + "mode": "managed", + "type": "kubernetes_pod", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "image_pull_policy": "prefix-Always-suffix" + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_pod_v1.test", + "mode": "managed", + "type": "kubernetes_pod_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "image_pull_policy": "prefix-Always-suffix" + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment.test", + "mode": "managed", + "type": "kubernetes_deployment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "image_pull_policy": "prefix-Always-suffix" + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment_v1.test", + "mode": "managed", + "type": "kubernetes_deployment_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "image_pull_policy": "prefix-Always-suffix" + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0091.compliant.json b/tests/packs/fixtures/SG_TF_0091.compliant.json new file mode 100644 index 00000000..4dd97e15 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0091.compliant.json @@ -0,0 +1,138 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "kubernetes_pod.test", + "mode": "managed", + "type": "kubernetes_pod", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "privileged": false + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_pod_v1.test", + "mode": "managed", + "type": "kubernetes_pod_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "privileged": false + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment.test", + "mode": "managed", + "type": "kubernetes_deployment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "privileged": false + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment_v1.test", + "mode": "managed", + "type": "kubernetes_deployment_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "privileged": false + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0091.violating.json b/tests/packs/fixtures/SG_TF_0091.violating.json new file mode 100644 index 00000000..c9b579bd --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0091.violating.json @@ -0,0 +1,138 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "kubernetes_pod.test", + "mode": "managed", + "type": "kubernetes_pod", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "privileged": true + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_pod_v1.test", + "mode": "managed", + "type": "kubernetes_pod_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "privileged": true + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment.test", + "mode": "managed", + "type": "kubernetes_deployment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "privileged": true + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment_v1.test", + "mode": "managed", + "type": "kubernetes_deployment_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "privileged": true + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0092.compliant.json b/tests/packs/fixtures/SG_TF_0092.compliant.json new file mode 100644 index 00000000..83aaa790 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0092.compliant.json @@ -0,0 +1,154 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "kubernetes_pod.test", + "mode": "managed", + "type": "kubernetes_pod", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "capabilities": [ + { + "add": null + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_pod_v1.test", + "mode": "managed", + "type": "kubernetes_pod_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "capabilities": [ + { + "add": null + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment.test", + "mode": "managed", + "type": "kubernetes_deployment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "capabilities": [ + { + "add": null + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment_v1.test", + "mode": "managed", + "type": "kubernetes_deployment_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "capabilities": [ + { + "add": null + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0092.violating.json b/tests/packs/fixtures/SG_TF_0092.violating.json new file mode 100644 index 00000000..b7fe37c8 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0092.violating.json @@ -0,0 +1,154 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "kubernetes_pod.test", + "mode": "managed", + "type": "kubernetes_pod", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "capabilities": [ + { + "add": "tirith_corpus_sentinel" + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_pod_v1.test", + "mode": "managed", + "type": "kubernetes_pod_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "capabilities": [ + { + "add": "tirith_corpus_sentinel" + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment.test", + "mode": "managed", + "type": "kubernetes_deployment", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "capabilities": [ + { + "add": "tirith_corpus_sentinel" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_deployment_v1.test", + "mode": "managed", + "type": "kubernetes_deployment_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "spec": [ + { + "template": [ + { + "spec": [ + { + "container": [ + { + "security_context": [ + { + "capabilities": [ + { + "add": "tirith_corpus_sentinel" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0093.compliant.json b/tests/packs/fixtures/SG_TF_0093.compliant.json new file mode 100644 index 00000000..54f5c46b --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0093.compliant.json @@ -0,0 +1,50 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "kubernetes_service_account.test", + "mode": "managed", + "type": "kubernetes_service_account", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "metadata": [ + { + "name": "tirith_corpus_sentinel" + } + ], + "automount_service_account_token": false + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_service_account_v1.test", + "mode": "managed", + "type": "kubernetes_service_account_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "metadata": [ + { + "name": "tirith_corpus_sentinel" + } + ], + "automount_service_account_token": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0093.violating.json b/tests/packs/fixtures/SG_TF_0093.violating.json new file mode 100644 index 00000000..c97a7121 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0093.violating.json @@ -0,0 +1,50 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "kubernetes_service_account.test", + "mode": "managed", + "type": "kubernetes_service_account", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "metadata": [ + { + "name": "default" + } + ], + "automount_service_account_token": true + }, + "after_unknown": {} + } + }, + { + "address": "kubernetes_service_account_v1.test", + "mode": "managed", + "type": "kubernetes_service_account_v1", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "metadata": [ + { + "name": "default" + } + ], + "automount_service_account_token": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0094.compliant.json b/tests/packs/fixtures/SG_TF_0094.compliant.json new file mode 100644 index 00000000..27292f6a --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0094.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "linode_firewall.test", + "mode": "managed", + "type": "linode_firewall", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "inbound_policy": "DROP" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0094.violating.json b/tests/packs/fixtures/SG_TF_0094.violating.json new file mode 100644 index 00000000..102178a1 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0094.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "linode_firewall.test", + "mode": "managed", + "type": "linode_firewall", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "inbound_policy": "prefix-DROP-suffix" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0095.compliant.json b/tests/packs/fixtures/SG_TF_0095.compliant.json new file mode 100644 index 00000000..a81f54fe --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0095.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "oci_file_storage_export.test", + "mode": "managed", + "type": "oci_file_storage_export", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "export_options": [ + { + "identity_squash": "tirith_corpus_sentinel" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0095.violating.json b/tests/packs/fixtures/SG_TF_0095.violating.json new file mode 100644 index 00000000..97e29113 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0095.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "oci_file_storage_export.test", + "mode": "managed", + "type": "oci_file_storage_export", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "export_options": [ + { + "identity_squash": "ROOT" + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0096.compliant.json b/tests/packs/fixtures/SG_TF_0096.compliant.json new file mode 100644 index 00000000..3975dc19 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0096.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "oci_core_instance.test", + "mode": "managed", + "type": "oci_core_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "launch_options": [ + { + "is_pv_encryption_in_transit_enabled": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0096.violating.json b/tests/packs/fixtures/SG_TF_0096.violating.json new file mode 100644 index 00000000..f93749e2 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0096.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "oci_core_instance.test", + "mode": "managed", + "type": "oci_core_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "launch_options": [ + { + "is_pv_encryption_in_transit_enabled": false + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0097.compliant.json b/tests/packs/fixtures/SG_TF_0097.compliant.json new file mode 100644 index 00000000..2d7b9412 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0097.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "oci_identity_authentication_policy.test", + "mode": "managed", + "type": "oci_identity_authentication_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "password_policy": [ + { + "is_lowercase_characters_required": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0097.violating.json b/tests/packs/fixtures/SG_TF_0097.violating.json new file mode 100644 index 00000000..2b2bd936 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0097.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "oci_identity_authentication_policy.test", + "mode": "managed", + "type": "oci_identity_authentication_policy", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "password_policy": [ + { + "is_lowercase_characters_required": false + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0098.compliant.json b/tests/packs/fixtures/SG_TF_0098.compliant.json new file mode 100644 index 00000000..bd1160b2 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0098.compliant.json @@ -0,0 +1,40 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "panos_ipsec_crypto_profile.test", + "mode": "managed", + "type": "panos_ipsec_crypto_profile", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "protocol": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + }, + { + "address": "panos_panorama_ipsec_crypto_profile.test", + "mode": "managed", + "type": "panos_panorama_ipsec_crypto_profile", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "protocol": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0098.violating.json b/tests/packs/fixtures/SG_TF_0098.violating.json new file mode 100644 index 00000000..634b335d --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0098.violating.json @@ -0,0 +1,40 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "panos_ipsec_crypto_profile.test", + "mode": "managed", + "type": "panos_ipsec_crypto_profile", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "protocol": "ah" + }, + "after_unknown": {} + } + }, + { + "address": "panos_panorama_ipsec_crypto_profile.test", + "mode": "managed", + "type": "panos_panorama_ipsec_crypto_profile", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "protocol": "ah" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0099.compliant.json b/tests/packs/fixtures/SG_TF_0099.compliant.json new file mode 100644 index 00000000..c046cb3d --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0099.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "panos_management_profile.test", + "mode": "managed", + "type": "panos_management_profile", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "telnet": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0099.violating.json b/tests/packs/fixtures/SG_TF_0099.violating.json new file mode 100644 index 00000000..c3b856e1 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0099.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "panos_management_profile.test", + "mode": "managed", + "type": "panos_management_profile", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "telnet": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0100.compliant.json b/tests/packs/fixtures/SG_TF_0100.compliant.json new file mode 100644 index 00000000..37a0a8d4 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0100.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "tencentcloud_clb_listener.test", + "mode": "managed", + "type": "tencentcloud_clb_listener", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "protocol": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0100.violating.json b/tests/packs/fixtures/SG_TF_0100.violating.json new file mode 100644 index 00000000..0612edf5 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0100.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "tencentcloud_clb_listener.test", + "mode": "managed", + "type": "tencentcloud_clb_listener", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "protocol": "TCP" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0101.compliant.json b/tests/packs/fixtures/SG_TF_0101.compliant.json new file mode 100644 index 00000000..19ab5bf2 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0101.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "tencentcloud_cbs_storage.test", + "mode": "managed", + "type": "tencentcloud_cbs_storage", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "encrypt": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0101.violating.json b/tests/packs/fixtures/SG_TF_0101.violating.json new file mode 100644 index 00000000..bb65e9b7 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0101.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "tencentcloud_cbs_storage.test", + "mode": "managed", + "type": "tencentcloud_cbs_storage", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "encrypt": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0102.compliant.json b/tests/packs/fixtures/SG_TF_0102.compliant.json new file mode 100644 index 00000000..d637fd5e --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0102.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "tencentcloud_instance.test", + "mode": "managed", + "type": "tencentcloud_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "disable_monitor_service": false + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0102.violating.json b/tests/packs/fixtures/SG_TF_0102.violating.json new file mode 100644 index 00000000..36c48085 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0102.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "tencentcloud_instance.test", + "mode": "managed", + "type": "tencentcloud_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "disable_monitor_service": true + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0103.compliant.json b/tests/packs/fixtures/SG_TF_0103.compliant.json new file mode 100644 index 00000000..5887f4f8 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0103.compliant.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "yandex_kubernetes_cluster.test", + "mode": "managed", + "type": "yandex_kubernetes_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "master": [ + { + "public_ip": false + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0103.violating.json b/tests/packs/fixtures/SG_TF_0103.violating.json new file mode 100644 index 00000000..b796973e --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0103.violating.json @@ -0,0 +1,27 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "yandex_kubernetes_cluster.test", + "mode": "managed", + "type": "yandex_kubernetes_cluster", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "master": [ + { + "public_ip": true + } + ] + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0104.compliant.json b/tests/packs/fixtures/SG_TF_0104.compliant.json new file mode 100644 index 00000000..08e87bc6 --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0104.compliant.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "yandex_kms_symmetric_key.test", + "mode": "managed", + "type": "yandex_kms_symmetric_key", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "rotation_period": "tirith_corpus_sentinel" + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/fixtures/SG_TF_0104.violating.json b/tests/packs/fixtures/SG_TF_0104.violating.json new file mode 100644 index 00000000..3aed6bfb --- /dev/null +++ b/tests/packs/fixtures/SG_TF_0104.violating.json @@ -0,0 +1,23 @@ +{ + "format_version": "1.2", + "terraform_version": "1.9.0", + "resource_changes": [ + { + "address": "yandex_kms_symmetric_key.test", + "mode": "managed", + "type": "yandex_kms_symmetric_key", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "rotation_period": null + }, + "after_unknown": {} + } + } + ] +} \ No newline at end of file diff --git a/tests/packs/test_bundled_packs.py b/tests/packs/test_bundled_packs.py new file mode 100644 index 00000000..cbe51c8d --- /dev/null +++ b/tests/packs/test_bundled_packs.py @@ -0,0 +1,145 @@ +""" +The bundled packs are shipped content, so they are tested like code. + +Three things are checked, and each has failed somewhere before: + + * the rename holds -- no upstream project name, check id or API vocabulary in a shipped file + * every policy is structurally valid, using tirith's own validator rather than a second schema + * every policy still *flips*: it passes its compliant fixture and fails its violating one + +The third is the one that earns its keep. A pack is generated once and then sits still while the +engine moves underneath it, so an engine change that silently turns a check into a no-op would +otherwise be invisible: the pack would keep running and keep reporting green. + +Fixtures live in tests/packs/fixtures and are deliberately not shipped in the wheel -- they are +how the pack is tested, not part of what it does. +""" + +import json +import logging +import os +import re + +import pytest + +from tirith import packs +from tirith.core.core import start_policy_evaluation_from_dict +from tirith.tui.validate import check_policy + +FIXTURES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures") + +ID_PATTERN = re.compile(r"^SG_TF_\d{4}$") + +# Kept in step with tools/sync_pack.py's own denylist. Duplicated on purpose: the generator +# refusing to write a leak and the test refusing to ship one are two independent gates, and a +# shared constant would let one edit disable both. +FORBIDDEN = ( + "checkov", + "bridgecrew", + "trivy", + "aquasecurity", + "steampipe", + "powerpipe", + "turbot", + "cfn-guard", + "kics", + "tfsec", + "terrascan", + "prowler", + "openssf", + "missing_block_result", + "missing_attribute_result", + "any_value", + "baseresourcevaluecheck", + "upstream", +) + + +def installed_packs(): + return packs.list_packs() + + +def all_policy_paths(): + found = [] + for pack in installed_packs(): + found += packs.pack_policy_paths(pack) + return found + + +def test_at_least_one_pack_is_bundled(): + # If package_data or MANIFEST.in ever drops the pack, everything else here passes vacuously. + assert installed_packs(), "no packs bundled -- check setup.py package_data and MANIFEST.in" + + +@pytest.mark.parametrize("pack", installed_packs(), ids=lambda p: p.name) +def test_manifest_matches_disk(pack): + on_disk = {os.path.basename(path) for _name, path in packs.pack_policy_paths(pack)} + declared = {os.path.basename(entry["path"]) for entry in pack.manifest["policies"]} + assert declared == on_disk + assert pack.manifest["count"] == len(on_disk) + + +@pytest.mark.parametrize("name,path", all_policy_paths(), ids=lambda value: os.path.basename(str(value))) +def test_policy_is_valid(name, path): + with open(path) as f: + policy = json.load(f) + errors = [finding for finding in check_policy(policy) if finding.severity == "error"] + assert not errors, f"{name}: {[str(finding) for finding in errors]}" + + +@pytest.mark.parametrize("name,path", all_policy_paths(), ids=lambda value: os.path.basename(str(value))) +def test_policy_id_is_a_stackguardian_id(name, path): + with open(path) as f: + policy = json.load(f) + assert ID_PATTERN.match(policy["meta"]["id"]), policy["meta"]["id"] + + +def test_policy_ids_are_unique(): + seen = {} + for name, path in all_policy_paths(): + with open(path) as f: + policy_id = json.load(f)["meta"]["id"] + assert policy_id not in seen, f"{name} reuses the id of {seen[policy_id]}" + seen[policy_id] = name + + +@pytest.mark.parametrize("pack", installed_packs(), ids=lambda p: p.name) +def test_no_upstream_name_survives(pack): + leaks = [] + for dirpath, _dirnames, filenames in os.walk(pack.path): + for filename in filenames: + full = os.path.join(dirpath, filename) + with open(full, encoding="utf-8") as f: + haystack = (filename + "\n" + f.read()).lower() + hits = [name for name in FORBIDDEN if name in haystack] + if re.search(r"\bckv\b|\bckv[0-9]*_", haystack): + hits.append("ckv") + if hits: + leaks.append(f"{filename}: {sorted(set(hits))}") + assert not leaks, leaks + + +@pytest.mark.parametrize("name,path", all_policy_paths(), ids=lambda value: os.path.basename(str(value))) +def test_policy_verdict_flips(name, path): + with open(path) as f: + policy = json.load(f) + policy_id = policy["meta"]["id"] + + compliant = os.path.join(FIXTURES_DIR, f"{policy_id}.compliant.json") + violating = os.path.join(FIXTURES_DIR, f"{policy_id}.violating.json") + if not (os.path.exists(compliant) and os.path.exists(violating)): + pytest.skip(f"no fixtures for {policy_id}") + + # The engine logs a warning for every tolerated provider miss, and a flip test drives + # thousands of them. + logging.disable(logging.CRITICAL) + try: + with open(compliant) as f: + good = start_policy_evaluation_from_dict(policy, json.load(f)) + with open(violating) as f: + bad = start_policy_evaluation_from_dict(policy, json.load(f)) + finally: + logging.disable(logging.NOTSET) + + assert good.get("final_result") is True, f"{name} did not pass its compliant document" + assert bad.get("final_result") is False, f"{name} did not fail its violating document" diff --git a/tools/sync_pack.py b/tools/sync_pack.py new file mode 100644 index 00000000..4377e9cc --- /dev/null +++ b/tools/sync_pack.py @@ -0,0 +1,393 @@ +"""Build a bundled policy pack from a tirith-policy-corpus checkout. + +The corpus translates upstream checks into tirith policy documents and grades them into nested +evidence tiers (`verified` > `exact` > `confirmed`). This turns one of those tiers into a pack +under `src/tirith/packs/`, which is what `tirith --pack ` runs. + +Two things happen on the way, and both are the point of having a tool rather than a copy: + +1. RENAMING. Shipped checks carry StackGuardian identifiers and nothing else -- no upstream + check ids, no upstream project names, in the id, the filename, the tags or the prose. The + mapping back to upstream stays in the corpus, in `pack_ids.json`, which is also what makes + the ids stable: an id is allocated once for a policy and reused on every later sync, so + re-running this with a wider tier appends and never renumbers. + +2. VERIFICATION. Nothing is written until every output has been re-read and checked for a + leaked upstream name. A rename that half-works is worse than one that fails loudly. + +Usage: + python3 tools/sync_pack.py --corpus ../tirith-policy-corpus --tier confirmed \ + --pack-name terraform-baseline --description "..." [--fixtures-from DIR] + +Tier selection is delegated to the corpus's own `tools/working_set.py`, so this tool never +has to restate what "confirmed" means. +""" + +from __future__ import annotations + +import argparse +import glob +import json +import os +import re +import shutil +import subprocess +import sys +from typing import Dict, List, Optional, Tuple + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +PACKS_DIR = os.path.join(ROOT, "src", "tirith", "packs") +FIXTURES_DIR = os.path.join(ROOT, "tests", "packs", "fixtures") + +# Data the corpus owns because it references upstream: the frozen id registry, and the prose +# rewrites for evaluator descriptions whose original text explains itself by naming the tool it +# was translated from. Keyed by "::" -- the join key the corpus uses +# everywhere, because upstream ids recur across frameworks and are not unique on their own. +ID_REGISTRY = "pack_ids.json" +OVERRIDES = "pack_overrides.json" + +ID_FORMAT = "SG_TF_{:04d}" +ID_PATTERN = re.compile(r"^SG_TF_\d{4}$") + +# Names that must not reach a shipped file. Checked case-insensitively over the whole document, +# including keys, after every rewrite. Kept explicit rather than clever: a missed name ships. +FORBIDDEN = ( + "checkov", + "bridgecrew", + "ckv", + "trivy", + "aquasecurity", + "aqua security", + "steampipe", + "powerpipe", + "turbot", + "cfn-guard", + "cfn_guard", + "guard-rules-registry", + "kics", + "tfsec", + "terrascan", + "prowler", + "regula", + "conftest", + "cloud custodian", + "openssf", + "scorecard", + "snyk", + "prisma", + "wiz.io", + # Not names, but upstream's API vocabulary, which reads as a translation artefact and points + # at one particular scanner just as plainly as its name would. + "missing_block_result", + "missing_attribute_result", + "any_value", + "baseresourcevaluecheck", + "jsonpath_not_exists", + "card rule", + "upstream", +) + +# Terraform resource-type prefix -> the cloud tag. Anything unlisted keeps its own prefix, so a +# new provider shows up as itself rather than silently vanishing. +CLOUD_BY_PREFIX = { + "aws": "aws", + "azurerm": "azure", + "azuread": "azure", + "google": "gcp", + "kubernetes": "kubernetes", + "alicloud": "alicloud", + "oci": "oci", + "tencentcloud": "tencentcloud", + "yandex": "yandex", + "digitalocean": "digitalocean", + "linode": "linode", + "panos": "panos", +} + +# Tags that say nothing a reader cannot already see: the provider is in `required_provider`. +DROPPED_TAGS = {"terraform", "json", "kubernetes_manifest"} + + +# --------------------------------------------------------------------------------------- corpus + + +def corpus_records(corpus: str) -> Dict[str, Dict]: + """Every translated record, keyed by its `out_path`.""" + rows: Dict[str, Dict] = {} + for pattern in ("records_*.jsonl", os.path.join("records2", "*.jsonl")): + for path in sorted(glob.glob(os.path.join(corpus, pattern))): + with open(path, encoding="utf-8") as fh: + for line in fh: + if not line.strip(): + continue + row = json.loads(line) + if row.get("status") == "translated" and row.get("out_path"): + rows[row["out_path"]] = row + return rows + + +def tier_paths(corpus: str, tier: str) -> List[str]: + """Delegate tier selection to the corpus, which is where the standard is defined.""" + out = subprocess.run( + [sys.executable, os.path.join("tools", "working_set.py"), "--tier", tier, "--list"], + cwd=corpus, + capture_output=True, + text=True, + check=True, + ) + return [line.strip() for line in out.stdout.splitlines() if line.strip()] + + +def corpus_commit(corpus: str) -> str: + out = subprocess.run(["git", "rev-parse", "HEAD"], cwd=corpus, capture_output=True, text=True, check=True) + return out.stdout.strip() + + +def load_json(path: str, default): + if not os.path.exists(path): + return default + with open(path, encoding="utf-8") as fh: + return json.load(fh) + + +# ------------------------------------------------------------------------------------ rewriting + + +def join_key(record: Dict) -> str: + """`(batch, policy_key)`, not policy_key alone: upstream ids recur across frameworks.""" + return f"{record.get('batch', '')}::{record['policy_key']}" + + +def allocate_ids(registry: Dict, keys: List[str]) -> Dict: + """Give every unseen key the next id. Never reassigns one that already exists.""" + ids = registry.setdefault("ids", {}) + next_id = registry.get("next", 1) + for key in keys: + if key not in ids: + ids[key] = ID_FORMAT.format(next_id) + next_id += 1 + registry["scheme"] = ID_FORMAT + registry["next"] = next_id + return registry + + +def _first_provider_args(policy: Dict) -> Dict: + for evaluator in policy.get("evaluators", []): + args = evaluator.get("provider_args") or {} + if args: + return args + return {} + + +def slug_for(policy: Dict) -> str: + """ + A readable filename half, from what the policy actually reads. + + `aws_s3_bucket` + `versioning.*.enabled` -> `aws_s3_bucket_versioning_enabled`. Wildcards and + list indices carry no meaning in a name, and a repeated word (the attribute restating the + resource) is dropped, so the result reads like a sentence rather than a path. + """ + args = _first_provider_args(policy) + parts = [args.get("terraform_resource_type") or args.get("kubernetes_kind") or ""] + parts.append( + args.get("terraform_resource_attribute") + or args.get("attribute_path") + or args.get("key_path") + or args.get("referenced_by") + or args.get("references_to") + or args.get("operation_type") + or "" + ) + + words: List[str] = [] + for part in parts: + for token in re.split(r"[^A-Za-z0-9]+", str(part)): + token = token.lower() + if not token or token.isdigit() or token == "": + continue + if token in words: + continue + words.append(token) + + slug = "_".join(words) or "policy" + return slug[:70].rstrip("_") + + +def rewrite_tags(policy: Dict) -> List[str]: + """Lowercase the upstream taxonomy, drop what the provider already says, add the cloud.""" + tags = [] + for tag in policy.get("meta", {}).get("tags", []) or []: + normalised = str(tag).strip().lower() + if not normalised or normalised in DROPPED_TAGS or normalised in tags: + continue + tags.append(normalised) + + resource_type = _first_provider_args(policy).get("terraform_resource_type") or "" + prefix = resource_type.split("_")[0] + cloud = CLOUD_BY_PREFIX.get(prefix) + if cloud: + cloud_tag = f"cloud:{cloud}" + if cloud_tag not in tags: + tags.insert(0, cloud_tag) + return tags + + +def apply_overrides(policy: Dict, override: Dict) -> None: + """Replace evaluator descriptions the corpus has supplied clean text for.""" + replacements = (override or {}).get("evaluator_descriptions") or {} + unused = set(replacements) + for evaluator in policy.get("evaluators", []): + if evaluator.get("id") in replacements: + evaluator["description"] = replacements[evaluator["id"]] + unused.discard(evaluator["id"]) + if unused: + raise SystemExit(f"override names evaluator(s) that do not exist: {', '.join(sorted(unused))}") + + +def forbidden_in(text: str) -> List[str]: + lowered = text.lower() + # `ckv` is matched on a word boundary; the others are distinctive enough to match anywhere. + hits = [name for name in FORBIDDEN if name != "ckv" and name in lowered] + if re.search(r"\bckv\b|\bckv[0-9]*_", lowered): + hits.append("ckv") + return hits + + +# ----------------------------------------------------------------------------------------- main + + +def build(corpus: str, tier: str, pack_name: str, description: str, fixtures_dir: Optional[str]) -> int: + records = corpus_records(corpus) + paths = tier_paths(corpus, tier) + if not paths: + raise SystemExit(f"tier '{tier}' selected no policies") + + registry_path = os.path.join(corpus, ID_REGISTRY) + registry = load_json(registry_path, {}) + # Keys beginning with "_" are commentary in the overrides file, not policies. + overrides = { + key: value for key, value in load_json(os.path.join(corpus, OVERRIDES), {}).items() if not key.startswith("_") + } + + selected: List[Tuple[str, Dict]] = [] + for rel in paths: + record = records.get(rel) + if record is None: + raise SystemExit(f"no translated record for {rel}") + selected.append((rel, record)) + + keys = sorted(join_key(record) for _rel, record in selected) + registry = allocate_ids(registry, keys) + + pack_dir = os.path.join(PACKS_DIR, pack_name) + policies_dir = os.path.join(pack_dir, "policies") + shutil.rmtree(pack_dir, ignore_errors=True) + os.makedirs(policies_dir) + + manifest_policies = [] + leaked: List[str] = [] + used_overrides = set() + + for rel, record in sorted(selected, key=lambda item: registry["ids"][join_key(item[1])]): + key = join_key(record) + policy_id = registry["ids"][key] + with open(os.path.join(corpus, rel), encoding="utf-8") as fh: + policy = json.load(fh) + + if key in overrides: + apply_overrides(policy, overrides[key]) + used_overrides.add(key) + + policy["meta"]["id"] = policy_id + policy["meta"]["tags"] = rewrite_tags(policy) + + filename = f"{policy_id}_{slug_for(policy)}.json" + rendered = json.dumps(policy, indent=2, ensure_ascii=False) + "\n" + + hits = forbidden_in(rendered) + forbidden_in(filename) + if hits: + leaked.append(f"{rel} -> {filename}: {', '.join(sorted(set(hits)))}") + continue + + with open(os.path.join(policies_dir, filename), "w", encoding="utf-8") as fh: + fh.write(rendered) + + manifest_policies.append( + { + "id": policy_id, + "path": f"policies/{filename}", + "name": policy["meta"].get("name", ""), + "fidelity": record.get("fidelity", "approximate"), + "required_provider": policy["meta"].get("required_provider", ""), + "tags": policy["meta"]["tags"], + } + ) + + if fixtures_dir: + stem = os.path.relpath(rel, "policies")[:-5].replace(os.sep, "__") + for kind in ("compliant", "violating"): + src = os.path.join(fixtures_dir, f"{stem}.{kind}.json") + if os.path.exists(src): + os.makedirs(FIXTURES_DIR, exist_ok=True) + shutil.copy(src, os.path.join(FIXTURES_DIR, f"{policy_id}.{kind}.json")) + + if leaked: + shutil.rmtree(pack_dir, ignore_errors=True) + print("refusing to write the pack -- upstream names survived the rename:", file=sys.stderr) + for line in leaked: + print(f" {line}", file=sys.stderr) + return 1 + + stale = set(overrides) - used_overrides + if stale: + print(f"warning: {len(stale)} override(s) matched no selected policy", file=sys.stderr) + + manifest = { + "name": pack_name, + "description": description, + "tier": tier, + "source": {"repo": "StackGuardian/tirith-policy-corpus", "commit": corpus_commit(corpus)}, + "required_providers": sorted({p["required_provider"] for p in manifest_policies}), + "count": len(manifest_policies), + "policies": manifest_policies, + } + with open(os.path.join(pack_dir, "pack.json"), "w", encoding="utf-8") as fh: + json.dump(manifest, fh, indent=2, ensure_ascii=False) + fh.write("\n") + + with open(registry_path, "w", encoding="utf-8") as fh: + json.dump(registry, fh, indent=2) + fh.write("\n") + + print(f"wrote {len(manifest_policies)} policies to {os.path.relpath(pack_dir, ROOT)}") + print(f"registry now holds {len(registry['ids'])} ids ({os.path.relpath(registry_path)})") + return 0 + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--corpus", required=True, help="path to a tirith-policy-corpus checkout") + parser.add_argument("--tier", default="confirmed", choices=("verified", "exact", "confirmed")) + parser.add_argument("--pack-name", required=True) + parser.add_argument("--description", default="") + parser.add_argument( + "--fixtures-from", + metavar="DIR", + help=( + "copy each policy's compliant/violating fixtures from DIR into tests/packs/fixtures. " + "The corpus does not commit fixtures/generated, so this has to be pointed at a " + "checkout that has actually generated them." + ), + ) + args = parser.parse_args() + return build( + os.path.abspath(args.corpus), + args.tier, + args.pack_name, + args.description, + os.path.abspath(args.fixtures_from) if args.fixtures_from else None, + ) + + +if __name__ == "__main__": + raise SystemExit(main())