From 860172ccfe073316db94d261a1d8d80d4910dd8e Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Tue, 27 Sep 2022 18:39:28 +0200 Subject: [PATCH] =?UTF-8?q?=E2=AD=90=EF=B8=8F=20terraform=20actions=20for?= =?UTF-8?q?=20plan=20and=20state=20files=20(#34)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christoph Hartmann Signed-off-by: Christoph Hartmann --- .github/test_files/tf/.gitignore | 1 + .github/test_files/tfplan/.gitignore | 4 ++ .github/test_files/tfplan/main.tf | 24 +++++++++ .../test_files/tfplan/policy/policy.mql.yaml | 23 ++++++++ .github/test_files/tfstate/.gitignore | 7 +++ .github/test_files/tfstate/build.sh | 6 +++ .github/test_files/tfstate/main.tf | 5 ++ .../test_files/tfstate/policy/policy.mql.yaml | 19 +++++++ .../{terraform.yaml => terraform-hcl.yaml} | 9 ++-- .github/workflows/terraform-plan.yaml | 46 ++++++++++++++++ .github/workflows/terraform-state.yaml | 54 +++++++++++++++++++ README.md | 4 +- terraform-hcl/README.md | 35 ++++++++++++ {terraform => terraform-hcl}/action.yaml | 4 +- terraform-plan/README.md | 35 ++++++++++++ terraform-plan/action.yaml | 52 ++++++++++++++++++ {terraform => terraform-state}/README.md | 6 +-- terraform-state/action.yaml | 52 ++++++++++++++++++ 18 files changed, 375 insertions(+), 11 deletions(-) create mode 100644 .github/test_files/tf/.gitignore create mode 100644 .github/test_files/tfplan/.gitignore create mode 100644 .github/test_files/tfplan/main.tf create mode 100644 .github/test_files/tfplan/policy/policy.mql.yaml create mode 100644 .github/test_files/tfstate/.gitignore create mode 100755 .github/test_files/tfstate/build.sh create mode 100644 .github/test_files/tfstate/main.tf create mode 100644 .github/test_files/tfstate/policy/policy.mql.yaml rename .github/workflows/{terraform.yaml => terraform-hcl.yaml} (76%) create mode 100644 .github/workflows/terraform-plan.yaml create mode 100644 .github/workflows/terraform-state.yaml create mode 100644 terraform-hcl/README.md rename {terraform => terraform-hcl}/action.yaml (93%) create mode 100644 terraform-plan/README.md create mode 100644 terraform-plan/action.yaml rename {terraform => terraform-state}/README.md (93%) create mode 100644 terraform-state/action.yaml diff --git a/.github/test_files/tf/.gitignore b/.github/test_files/tf/.gitignore new file mode 100644 index 0000000..bda0c9b --- /dev/null +++ b/.github/test_files/tf/.gitignore @@ -0,0 +1 @@ +.terraform/* \ No newline at end of file diff --git a/.github/test_files/tfplan/.gitignore b/.github/test_files/tfplan/.gitignore new file mode 100644 index 0000000..7324534 --- /dev/null +++ b/.github/test_files/tfplan/.gitignore @@ -0,0 +1,4 @@ +.terraform/* +plan +plan.json +.terraform.lock.hcl \ No newline at end of file diff --git a/.github/test_files/tfplan/main.tf b/.github/test_files/tfplan/main.tf new file mode 100644 index 0000000..cb90e8b --- /dev/null +++ b/.github/test_files/tfplan/main.tf @@ -0,0 +1,24 @@ +terraform { + required_providers { + github = { + source = "integrations/github" + version = "~> 4.0" + } + } +} + +# Configure the GitHub Provider +provider "github" {} + + +resource "github_repository" "example" { + name = "example" + description = "My awesome codebase" + + visibility = "public" + + template { + owner = "github" + repository = "terraform-module-template" + } +} \ No newline at end of file diff --git a/.github/test_files/tfplan/policy/policy.mql.yaml b/.github/test_files/tfplan/policy/policy.mql.yaml new file mode 100644 index 0000000..2f2b0b0 --- /dev/null +++ b/.github/test_files/tfplan/policy/policy.mql.yaml @@ -0,0 +1,23 @@ +policies: + - uid: terraform-plan-sample-policy + name: Terraform Plan - GitHub + version: "1.1.0" + authors: + - name: Mondoo, Inc. + email: hello@mondoo.com + specs: + - title: GitHub Test + asset_filter: + query: | + platform.name == "terraform-plan" + terraform.plan.resourceChanges.any( providerName == "registry.terraform.io/integrations/github") + scoring_queries: + terraform-github-repo-visibility: null +queries: + - uid: terraform-github-repo-visibility + title: Check GitHub repository visibility + query: | + terraform.plan.resourceChanges.where( type == "github_repository" && mode == "managed") { + name == "example" + change.after["visibility"] = "public" + } diff --git a/.github/test_files/tfstate/.gitignore b/.github/test_files/tfstate/.gitignore new file mode 100644 index 0000000..f791a16 --- /dev/null +++ b/.github/test_files/tfstate/.gitignore @@ -0,0 +1,7 @@ +.terraform/* +.terraform.lock.hcl +plan +plan.json +state.json +terraform.tfstate +terraform.tfstate.backup \ No newline at end of file diff --git a/.github/test_files/tfstate/build.sh b/.github/test_files/tfstate/build.sh new file mode 100755 index 0000000..84f6067 --- /dev/null +++ b/.github/test_files/tfstate/build.sh @@ -0,0 +1,6 @@ +#!/bin/sh +terraform init +terraform plan -out plan +terraform apply plan +terraform show -json plan > plan.json +terraform show -json terraform.tfstate > state.json \ No newline at end of file diff --git a/.github/test_files/tfstate/main.tf b/.github/test_files/tfstate/main.tf new file mode 100644 index 0000000..2680bbd --- /dev/null +++ b/.github/test_files/tfstate/main.tf @@ -0,0 +1,5 @@ +resource "null_resource" "ls" { + provisioner "local-exec" { + command = "ls" + } +} \ No newline at end of file diff --git a/.github/test_files/tfstate/policy/policy.mql.yaml b/.github/test_files/tfstate/policy/policy.mql.yaml new file mode 100644 index 0000000..880bc27 --- /dev/null +++ b/.github/test_files/tfstate/policy/policy.mql.yaml @@ -0,0 +1,19 @@ +policies: + - uid: terraform-state-sample-policy + name: Terraform State - GitHub + version: "1.1.0" + authors: + - name: Mondoo, Inc. + email: hello@mondoo.com + specs: + - title: GitHub Test + asset_filter: + query: | + platform.name == "terraform-state" + scoring_queries: + terraform-state-check-null-provider: null +queries: + - uid: terraform-state-check-null-provider + title: Check null provider + query: | + terraform.state.rootModule.resources { providerName == "registry.terraform.io/hashicorp/null" } diff --git a/.github/workflows/terraform.yaml b/.github/workflows/terraform-hcl.yaml similarity index 76% rename from .github/workflows/terraform.yaml rename to .github/workflows/terraform-hcl.yaml index 8ea9145..0de2dea 100644 --- a/.github/workflows/terraform.yaml +++ b/.github/workflows/terraform-hcl.yaml @@ -1,10 +1,10 @@ -name: Terraform Scanning +name: Terraform HCL Scanning Tests on: pull_request: push: paths: - "action.yaml" - - "terraform/*" + - "terraform-hcl/*" - ".github/test_files/**" branches: - "main" @@ -16,9 +16,8 @@ jobs: name: Test Terraform scanning steps: - uses: actions/checkout@v3 - - - name: Scan Terraform - uses: ./terraform + - name: Scan Terraform HCL + uses: ./terraform-hcl with: service-account-credentials: ${{ secrets.MONDOO_SERVICE_ACCOUNT }} path: ./.github/test_files/tf diff --git a/.github/workflows/terraform-plan.yaml b/.github/workflows/terraform-plan.yaml new file mode 100644 index 0000000..f19401f --- /dev/null +++ b/.github/workflows/terraform-plan.yaml @@ -0,0 +1,46 @@ +name: Terraform Plan Scanning Tests +on: + pull_request: + push: + paths: + - "action.yaml" + - "terraform-plan/*" + - "terraform-state/*" + - ".github/test_files/**" + branches: + - "main" + tags: ["v*.*.*"] + +jobs: + terraform-tests: + runs-on: ubuntu-latest + name: Test Terraform scanning + steps: + - uses: actions/checkout@v3 + + # run terraform plan checks + - uses: hashicorp/setup-terraform@v2 + with: + # super important setting, otherwise you cannot pipe terraform show -json + # see https://stackoverflow.com/questions/66496105/how-can-i-remove-all-the-extraneous-output-from-redirected-output-in-github-acti + terraform_wrapper: false + - run: terraform init + working-directory: ./.github/test_files/tfplan + - name: Write terraform plan + run: terraform plan -out plan + working-directory: ./.github/test_files/tfplan + - name: Export terraform plan to json + shell: bash + run: terraform show -json plan > plan.json + working-directory: ./.github/test_files/tfplan + - name: Upload terraform plan + uses: actions/upload-artifact@v3 + with: + name: terraform-plan.json + path: .github/test_files/tfplan/plan.json + - name: Scan Terraform Plan + uses: ./terraform-plan + with: + service-account-credentials: ${{ secrets.MONDOO_SERVICE_ACCOUNT }} + path: ".github/test_files/tfplan/plan.json" + args: "--policy-bundle .github/test_files/tfplan/policy/policy.mql.yaml" diff --git a/.github/workflows/terraform-state.yaml b/.github/workflows/terraform-state.yaml new file mode 100644 index 0000000..9c58462 --- /dev/null +++ b/.github/workflows/terraform-state.yaml @@ -0,0 +1,54 @@ +name: Terraform State Scanning Tests +on: + pull_request: + push: + paths: + - "action.yaml" + - "terraform-plan/*" + - "terraform-state/*" + - ".github/test_files/**" + branches: + - "main" + tags: ["v*.*.*"] + +jobs: + terraform-tests: + runs-on: ubuntu-latest + name: Test Terraform scanning + steps: + - uses: actions/checkout@v3 + + # run terraform plan checks + - uses: hashicorp/setup-terraform@v2 + with: + # super important setting, otherwise you cannot pipe terraform show -json + # see https://stackoverflow.com/questions/66496105/how-can-i-remove-all-the-extraneous-output-from-redirected-output-in-github-acti + terraform_wrapper: false + - run: terraform init + working-directory: ./.github/test_files/tfstate + - name: Write terraform plan + run: terraform plan -out plan + working-directory: ./.github/test_files/tfstate + - name: Export terraform plan to json + shell: bash + run: terraform show -json plan > plan.json + working-directory: ./.github/test_files/tfstate + - name: Export terraform state to json + shell: bash + run: | + terraform apply plan + terraform show -json terraform.tfstate > state.json + working-directory: ./.github/test_files/tfstate + - name: Upload terraform plan + uses: actions/upload-artifact@v3 + with: + name: terraform + path: | + .github/test_files/tfstate/plan.json + .github/test_files/tfstate/state.json + - name: Scan Terraform State + uses: ./terraform-state + with: + service-account-credentials: ${{ secrets.MONDOO_SERVICE_ACCOUNT }} + path: ".github/test_files/tfstate/state.json" + args: "--policy-bundle .github/test_files/tfstate/policy/policy.mql.yaml" diff --git a/README.md b/README.md index fa64128..ac5cab9 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ A set of GitHub Action for using Mondoo to check for vulnerabilities and misconf - [Kubernetes Manifest](k8s-manifest) - Scan Kubernetes manifests for misconfigurations before applying changes to the cluster. - [Policy](policy) - Publish Mondoo policies to Mondoo Platform using GitHub Actions. - [Setup](setup) - Install and configure Mondoo into any existing GitHub Action workflow. -- [Terraform](terraform) - Scan HashiCorp Terraform code for security misconfigurations. +- [Terraform HCL](terraform-hcl) - Scan HashiCorp Terraform HCL code for security misconfigurations. +- [Terraform Plan](terraform-plan) - Scan HashiCorp Terraform Plan for security misconfigurations. +- [Terraform State](terraform-state) - Scan HashiCorp Terraform State output for security misconfigurations. ## Service Accounts diff --git a/terraform-hcl/README.md b/terraform-hcl/README.md new file mode 100644 index 0000000..38a5e65 --- /dev/null +++ b/terraform-hcl/README.md @@ -0,0 +1,35 @@ +# Mondoo Terraform HCL Action + +A [GitHub Action](https://github.com/features/actions) for testing [HashiCorp Terraform](https://terraform.io) [HCL code]](https://www.terraform.io/language/syntax/configuration) for security misconfigurations. + +## Properties + +The Terraform Action has properties which are passed to the underlying image. These are passed to the action using `with`. + +| Property | Required | Default | Description | +| ----------------------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `args` | false | | Additional arguments to pass to Mondoo Client. | +| `log-level` | false | info | Sets the log level: error, warn, info, debug, trace (default "info") | +| `output` | false | compact | Set the output format for scan results: compact, yaml, json, junit, csv, summary, full, report (default "compact") | +| `path` | true | | Path to the Terraform working directory. | +| `score-threshold` | false | 0 | Sets the score threshold for scans. Scores that fall below the threshold will exit 1. (default "0" - job continues regardless of the score returned by a scan). | +| `service-account-credentials` | true | | Base64 encoded [service account credentials](https://mondoo.com/docs/platform/service_accounts/#creating-service-accounts) used to authenticate with Mondoo Platform | + +## Scan Terraform working directory + +You can use the Action as follows: + +```yaml +name: Mondoo Terraform scan +on: + push: + paths: + - "terraform/main.tf" +jobs: + steps: + - uses: actions/checkout@v3 + - uses: mondoohq/actions/terraform@main + with: + service-account-credentials: ${{ secrets.MONDOO_SERVICE_ACCOUNT }} + path: terraform +``` diff --git a/terraform/action.yaml b/terraform-hcl/action.yaml similarity index 93% rename from terraform/action.yaml rename to terraform-hcl/action.yaml index b946e8d..aa1d939 100644 --- a/terraform/action.yaml +++ b/terraform-hcl/action.yaml @@ -1,5 +1,5 @@ -name: "Mondoo Terraform GitHub Action" -description: "Scan HashiCorp Terraform for misconfigurations with Mondoo" +name: "Mondoo Terraform HCL GitHub Action" +description: "Scan HashiCorp Terraform HCL for misconfigurations with Mondoo" branding: icon: "shield" color: "purple" diff --git a/terraform-plan/README.md b/terraform-plan/README.md new file mode 100644 index 0000000..a24d646 --- /dev/null +++ b/terraform-plan/README.md @@ -0,0 +1,35 @@ +# Mondoo Terraform Plan Action + +A [GitHub Action](https://github.com/features/actions) for testing [HashiCorp Terraform](https://terraform.io) code for security misconfigurations. Mondoo policies will verity [Terraform's HCL syntax]](https://www.terraform.io/language/syntax/configuration). + +## Properties + +The Terraform Action has properties which are passed to the underlying image. These are passed to the action using `with`. + +| Property | Required | Default | Description | +| ----------------------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `args` | false | | Additional arguments to pass to Mondoo Client. | +| `log-level` | false | info | Sets the log level: error, warn, info, debug, trace (default "info") | +| `output` | false | compact | Set the output format for scan results: compact, yaml, json, junit, csv, summary, full, report (default "compact") | +| `path` | true | | Path to the Terraform working directory. | +| `score-threshold` | false | 0 | Sets the score threshold for scans. Scores that fall below the threshold will exit 1. (default "0" - job continues regardless of the score returned by a scan). | +| `service-account-credentials` | true | | Base64 encoded [service account credentials](https://mondoo.com/docs/platform/service_accounts/#creating-service-accounts) used to authenticate with Mondoo Platform | + +## Scan Terraform working directory + +You can use the Action as follows: + +```yaml +name: Mondoo Terraform Plan scan +on: + push: + paths: + - "terraform/main.tf" +jobs: + steps: + - uses: actions/checkout@v3 + - uses: mondoohq/actions/terraform@main + with: + service-account-credentials: ${{ secrets.MONDOO_SERVICE_ACCOUNT }} + path: terraform +``` diff --git a/terraform-plan/action.yaml b/terraform-plan/action.yaml new file mode 100644 index 0000000..3f32061 --- /dev/null +++ b/terraform-plan/action.yaml @@ -0,0 +1,52 @@ +name: "Mondoo Terraform Plan GitHub Action" +description: "Scan HashiCorp Terraform Plan for misconfigurations with Mondoo" +branding: + icon: "shield" + color: "purple" +inputs: + args: + description: >- + Additional arguments to pass to Mondoo Client. + required: false + log-level: + description: >- + Sets the log level: error, warn, info, debug, trace (default "info") + default: info + required: false + output: + description: >- + Set the output format for scan results: compact, yaml, json, junit, csv, summary, full, report (default "compact") + default: compact + required: false + path: + description: Path to the Terraform working directory. + required: true + score-threshold: + description: >- + Sets the score threshold for scans. Scores that fall below the threshold will exit 1. (default "0" - job continues regardless of the score returned by a scan). + default: "0" + required: false + service-account-credentials: + description: "Base64 encoded service account credentials used to authenticate with Mondoo Platform" + required: true +runs: + using: "composite" + steps: + - name: Install Mondoo Client + shell: bash + run: | + echo Installing Mondoo Client... + echo ${{ inputs.service-account-credentials }} | base64 -d > mondoo.json + curl -sSL https://mondoo.com/install.sh | bash + - name: Mondoo status + shell: bash + run: mondoo status --config mondoo.json + - name: Scan Terraform + shell: bash + run: > + mondoo scan terraform plan "${{ inputs.path }}" + --log-level "${{ inputs.log-level }}" + --output "${{ inputs.output }}" + --score-threshold "${{ inputs.score-threshold }}" + --config mondoo.json + ${{ inputs.args }} diff --git a/terraform/README.md b/terraform-state/README.md similarity index 93% rename from terraform/README.md rename to terraform-state/README.md index 111d644..e2d2714 100644 --- a/terraform/README.md +++ b/terraform-state/README.md @@ -1,6 +1,6 @@ -# Mondoo Terraform Action +# Mondoo Terraform State Action -A [GitHub Action](https://github.com/features/actions) for testing [HashiCorp Terraform](https://terraform.io) code for security misconfigurations. +A [GitHub Action](https://github.com/features/actions) for testing [HashiCorp Terraform](https://terraform.io) state files for security misconfigurations. ## Properties @@ -20,7 +20,7 @@ The Terraform Action has properties which are passed to the underlying image. Th You can use the Action as follows: ```yaml -name: Mondoo Terraform scan +name: Mondoo Terraform State scan on: push: paths: diff --git a/terraform-state/action.yaml b/terraform-state/action.yaml new file mode 100644 index 0000000..4dacd03 --- /dev/null +++ b/terraform-state/action.yaml @@ -0,0 +1,52 @@ +name: "Mondoo Terraform State GitHub Action" +description: "Scan HashiCorp Terraform State for misconfigurations with Mondoo" +branding: + icon: "shield" + color: "purple" +inputs: + args: + description: >- + Additional arguments to pass to Mondoo Client. + required: false + log-level: + description: >- + Sets the log level: error, warn, info, debug, trace (default "info") + default: info + required: false + output: + description: >- + Set the output format for scan results: compact, yaml, json, junit, csv, summary, full, report (default "compact") + default: compact + required: false + path: + description: Path to the Terraform working directory. + required: true + score-threshold: + description: >- + Sets the score threshold for scans. Scores that fall below the threshold will exit 1. (default "0" - job continues regardless of the score returned by a scan). + default: "0" + required: false + service-account-credentials: + description: "Base64 encoded service account credentials used to authenticate with Mondoo Platform" + required: true +runs: + using: "composite" + steps: + - name: Install Mondoo Client + shell: bash + run: | + echo Installing Mondoo Client... + echo ${{ inputs.service-account-credentials }} | base64 -d > mondoo.json + curl -sSL https://mondoo.com/install.sh | bash + - name: Mondoo status + shell: bash + run: mondoo status --config mondoo.json + - name: Scan Terraform + shell: bash + run: > + mondoo scan terraform state ${{ inputs.path }} + --log-level ${{ inputs.log-level }} + --output ${{ inputs.output }} + --score-threshold ${{ inputs.score-threshold }} + --config mondoo.json + ${{ inputs.args }}