diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..f67eda9 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @rhythmictech/engineering diff --git a/.github/workflows/misspell.yaml b/.github/workflows/misspell.yaml new file mode 100644 index 0000000..6574e3d --- /dev/null +++ b/.github/workflows/misspell.yaml @@ -0,0 +1,23 @@ +--- +name: misspell +on: + push: + branches: + - main + - master + - prod + - develop + +jobs: + misspell: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: misspell + uses: reviewdog/action-misspell@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + locale: "US" + reporter: github-check + filter_mode: nofilter + level: error diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml new file mode 100644 index 0000000..398767c --- /dev/null +++ b/.github/workflows/pre-commit.yaml @@ -0,0 +1,30 @@ +--- +name: pre-commit-check +on: + push: + branches: + - master + - prod + - develop + +jobs: + pre-commit-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install prerequisites + run: ./bin/install-ubuntu.sh + - name: initialize Terraform + run: terraform init --backend=false + - name: pre-commit + uses: pre-commit/action@v2.0.3 + env: + AWS_DEFAULT_REGION: us-east-1 + # many of these are covered by better reviewdog linters below + SKIP: >- + terraform_tflint_deep, + no-commit-to-branch, + terraform_tflint_nocreds, + terraform_tfsec diff --git a/.github/workflows/pullRequest.yaml b/.github/workflows/pullRequest.yaml new file mode 100644 index 0000000..8f1eba5 --- /dev/null +++ b/.github/workflows/pullRequest.yaml @@ -0,0 +1,81 @@ +--- +name: pull request +on: + pull_request: + +jobs: + # TODO: #22 add job using https://github.com/reviewdog/action-alex + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install prerequisites + run: ./bin/install-ubuntu.sh + - name: initialize Terraform + run: terraform init --backend=false + - name: pre-commit + uses: pre-commit/action@v2.0.3 + env: + AWS_DEFAULT_REGION: us-east-1 + # many of these are covered by better reviewdog linters below + SKIP: >- + terraform_tflint_deep, + no-commit-to-branch, + terraform_tflint_nocreds, + terraform_tfsec + tflint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install prerequisites + run: ./bin/install-ubuntu.sh + - name: Terraform init + run: terraform init --backend=false + - name: tflint + uses: reviewdog/action-tflint@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-check + filter_mode: added + flags: --module + level: error + tfsec: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install prerequisites + run: ./bin/install-ubuntu.sh + - name: Terraform init + run: terraform init --backend=false + - name: tfsec + uses: reviewdog/action-tfsec@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-check + filter_mode: added + level: warning + misspell: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: misspell + uses: reviewdog/action-misspell@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + locale: "US" + reporter: github-pr-check + filter_mode: added + level: error + yamllint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: yamllint + uses: reviewdog/action-yamllint@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-check + filter_mode: added + level: error diff --git a/.github/workflows/tflint.yaml b/.github/workflows/tflint.yaml new file mode 100644 index 0000000..10457b5 --- /dev/null +++ b/.github/workflows/tflint.yaml @@ -0,0 +1,27 @@ +--- +name: tflint +on: + push: + branches: + - main + - master + - prod + - develop + +jobs: + tflint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install prerequisites + run: ./bin/install-ubuntu.sh + - name: Terraform init + run: terraform init --backend=false + - name: tflint + uses: reviewdog/action-tflint@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-check + filter_mode: nofilter + flags: --module + level: error diff --git a/.github/workflows/tfsec.yaml b/.github/workflows/tfsec.yaml new file mode 100644 index 0000000..2f75a3e --- /dev/null +++ b/.github/workflows/tfsec.yaml @@ -0,0 +1,26 @@ +--- +name: tfsec +on: + push: + branches: + - main + - master + - prod + - develop + +jobs: + tfsec: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install prerequisites + run: ./bin/install-ubuntu.sh + - name: Terraform init + run: terraform init --backend=false + - name: tfsec + uses: reviewdog/action-tfsec@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-check + filter_mode: nofilter + level: error diff --git a/.github/workflows/yamllint.yaml b/.github/workflows/yamllint.yaml new file mode 100644 index 0000000..0b6f93a --- /dev/null +++ b/.github/workflows/yamllint.yaml @@ -0,0 +1,22 @@ +--- +name: yamllint +on: + push: + branches: + - main + - master + - prod + - develop + +jobs: + yamllint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: yamllint + uses: reviewdog/action-yamllint@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-check + filter_mode: nofilter + level: error diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a36b56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# .tfvars files +*.tfvars + +# macs +.DS_Store + +# temp folders +tmp + +# modules should not submit lock files +.terraform.lock.hcl diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..898f6eb --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,54 @@ +# excluding a few checks because it isn't coping well with the hacky way we do the rds monitoring lambda +exclude: ".terraform" +repos: + - repo: https://github.com/antonbabenko/pre-commit-terraform + rev: v1.88.0 + hooks: + - id: terraform_docs + always_run: true + - id: terraform_fmt + - id: terraform_validate + args: + - --hook-config=--retry-once-with-cleanup=true + exclude: examples\/ + - id: terraform_tflint + alias: terraform_tflint_nocreds + name: terraform_tflint_nocreds + - id: terraform_trivy + args: + - --args=--skip-dirs="**/.terraform,examples/*" + - id: terraform_providers_lock + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-json + - id: check-merge-conflict + - id: check-symlinks + - id: check-yaml + args: + - --unsafe + - id: detect-private-key + - id: end-of-file-fixer + - id: mixed-line-ending + args: + - --fix=lf + - id: no-commit-to-branch + args: + - --branch + - main + - --branch + - master + - --branch + - prod + - id: pretty-format-json + args: + - --autofix + - --top-keys=name,Name + - id: trailing-whitespace + args: + - --markdown-linebreak-ext=md + exclude: README.md +ci: + skip: [terraform_docs, terraform_fmt, terraform_tflint, terraform_tfsec, tflock] diff --git a/.terraform-version b/.terraform-version new file mode 100644 index 0000000..f1ce147 --- /dev/null +++ b/.terraform-version @@ -0,0 +1 @@ +latest:^1.5 diff --git a/.tflint.hcl b/.tflint.hcl new file mode 100644 index 0000000..5379e3b --- /dev/null +++ b/.tflint.hcl @@ -0,0 +1,50 @@ +config { + module = true +} + +plugin "aws" { + enabled = true + version = "0.12.0" + source = "github.com/terraform-linters/tflint-ruleset-aws" +} + +rule "terraform_deprecated_interpolation" { + enabled = true +} + +rule "terraform_unused_declarations" { + enabled = true +} + +rule "terraform_comment_syntax" { + enabled = true +} + +rule "terraform_documented_outputs" { + enabled = true +} + +rule "terraform_documented_variables" { + enabled = true +} + +rule "terraform_typed_variables" { + enabled = true +} + +rule "terraform_module_pinned_source" { + enabled = true +} + +rule "terraform_naming_convention" { + enabled = true + format = "snake_case" +} + +rule "terraform_required_version" { + enabled = false +} + +rule "terraform_required_providers" { + enabled = true +} diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..e1a518a --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,2 @@ +truthy: + check-keys: false diff --git a/README.md b/README.md new file mode 100644 index 0000000..4af743a --- /dev/null +++ b/README.md @@ -0,0 +1,94 @@ +# terraform-aws-rhythmic-account-monitor +Configures AWS health and account related notifications + +[![tflint](https://github.com/rhythmictech/terraform-aws-rhythmic-account-monitor/workflows/tflint/badge.svg?branch=master&event=push)](https://github.com/rhythmictech/terraform-aws-rhythmic-account-monitor/actions?query=workflow%3Atflint+event%3Apush+branch%3Amaster) +[![tfsec](https://github.com/rhythmictech/terraform-aws-rhythmic-account-monitor/workflows/tfsec/badge.svg?branch=master&event=push)](https://github.com/rhythmictech/terraform-aws-rhythmic-account-monitor/actions?query=workflow%3Atfsec+event%3Apush+branch%3Amaster) +[![yamllint](https://github.com/rhythmictech/terraform-aws-rhythmic-account-monitor/workflows/yamllint/badge.svg?branch=master&event=push)](https://github.com/rhythmictech/terraform-aws-rhythmic-account-monitor/actions?query=workflow%3Ayamllint+event%3Apush+branch%3Amaster) +[![misspell](https://github.com/rhythmictech/terraform-aws-rhythmic-account-monitor/workflows/misspell/badge.svg?branch=master&event=push)](https://github.com/rhythmictech/terraform-aws-rhythmic-account-monitor/actions?query=workflow%3Amisspell+event%3Apush+branch%3Amaster) +[![pre-commit-check](https://github.com/rhythmictech/terraform-aws-rhythmic-account-monitor/workflows/pre-commit-check/badge.svg?branch=master&event=push)](https://github.com/rhythmictech/terraform-aws-rhythmic-account-monitor/actions?query=workflow%3Apre-commit-check+event%3Apush+branch%3Amaster) +follow on Twitter + +## Example +Here's what using the module will look like +```hcl +module "example" { + source = "rhythmictech/rhythmic-account-monitor/aws" + datadog_api_key_secret_arn = "" +} +``` + +## About +Rhythmic is an AWS Managed Services Provider. We rely heavily on automation to deliver our services, ingesting configuration, event and state information from AWS via listeners (e.g., EventBridge and SNS), services (e.g., Anomaly Detection), and APIs via custom scripts (e.g., Trusted Advisor). + +We open source the vast majority of the resources we use to deliver our managed services because transparency is one of our principles. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.5 | +| [aws](#requirement\_aws) | >= 4.62 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | 5.36.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [tags](#module\_tags) | rhythmictech/tags/terraform | ~> 1.1.1 | + +## Resources + +| Name | Type | +|------|------| +| [aws_accessanalyzer_analyzer.analyzer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/accessanalyzer_analyzer) | resource | +| [aws_accessanalyzer_analyzer.analyzer_unused](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/accessanalyzer_analyzer) | resource | +| [aws_cloudwatch_event_rule.analyzer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | +| [aws_cloudwatch_event_rule.backup](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | +| [aws_cloudwatch_event_rule.backup_event](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | +| [aws_cloudwatch_event_rule.backup_vaultlock](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | +| [aws_cloudwatch_event_rule.glacier_vaultlock](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource | +| [aws_cloudwatch_event_target.analyzer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | +| [aws_cloudwatch_event_target.backup](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | +| [aws_cloudwatch_event_target.backup_event](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | +| [aws_cloudwatch_event_target.backup_vaultlock](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | +| [aws_cloudwatch_event_target.glacier_vaultlock](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource | +| [aws_sns_topic.account_alerts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic) | resource | +| [aws_sns_topic_policy.account_alerts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic_policy) | resource | +| [aws_sns_topic_subscription.account_alerts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic_subscription) | resource | +| [aws_iam_policy_document.account_alerts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_secretsmanager_secret.datadog_api_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/secretsmanager_secret) | data source | +| [aws_secretsmanager_secret_version.datadog_api_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/secretsmanager_secret_version) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [datadog\_api\_key\_secret\_arn](#input\_datadog\_api\_key\_secret\_arn) | ARN of the AWS Secret containing the Datadog API key | `string` | n/a | yes | +| [enable\_iam\_access\_analyzer](#input\_enable\_iam\_access\_analyzer) | A boolean flag to enable/disable IAM Access Analyzer | `bool` | `false` | no | +| [iam\_analyzer\_unused\_access\_age](#input\_iam\_analyzer\_unused\_access\_age) | The age in days after which IAM access is considered unused. | `number` | `90` | no | +| [tags](#input\_tags) | User-Defined tags | `map(string)` | `{}` | no | + +## Outputs + +No outputs. + + +## Getting Started +This workflow has a few prerequisites which are installed through the `./bin/install-x.sh` scripts and are linked below. The install script will also work on your local machine. + +- [pre-commit](https://pre-commit.com) +- [terraform](https://terraform.io) +- [tfenv](https://github.com/tfutils/tfenv) +- [terraform-docs](https://github.com/segmentio/terraform-docs) +- [tfsec](https://github.com/tfsec/tfsec) +- [tflint](https://github.com/terraform-linters/tflint) + +We use `tfenv` to manage `terraform` versions, so the version is defined in the `versions.tf` and `tfenv` installs the latest compliant version. +`pre-commit` is like a package manager for scripts that integrate with git hooks. We use them to run the rest of the tools before apply. +`terraform-docs` creates the beautiful docs (above), `tfsec` scans for security no-nos, `tflint` scans for best practices. diff --git a/backup.tf b/backup.tf new file mode 100644 index 0000000..d3c8dcb --- /dev/null +++ b/backup.tf @@ -0,0 +1,49 @@ +resource "aws_cloudwatch_event_rule" "backup" { + + name = "backup-events-monitor" + description = "Capture AWS Backup events" + + event_pattern = jsonencode({ + source = ["aws.backup"] + detail-type = ["AWS API Call via CloudTrail"] + detail = { + eventSource = ["backup.amazonaws.com"] + eventName = [ + "DeleteBackupPlan", + "DeleteBackupSelection", + "DeleteBackupVault", + "DeleteRecoveryPoint", + "PutBackupVaultAccessPolicy", + "UpdateRecoveryPointLifecycle" + ] + } + }) +} + +resource "aws_cloudwatch_event_target" "backup" { + arn = aws_sns_topic.account_alerts.arn + rule = aws_cloudwatch_event_rule.backup.name + target_id = "SendToSNS" +} + +resource "aws_cloudwatch_event_rule" "backup_event" { + + name_prefix = "backup-events-monitor" + description = "AWS Backup failures" + + event_pattern = < tflint.zip && unzip tflint.zip && rm tflint.zip && sudo mv tflint /usr/bin/ +go install github.com/aquasecurity/tfsec/cmd/tfsec@latest +git clone https://github.com/tfutils/tfenv.git ~/.tfenv || true +mkdir -p ~/.local/bin/ +. ~/.profile +ln -s ~/.tfenv/bin/* ~/.local/bin + +echo 'installing pre-commit hooks' +pre-commit install + +echo 'setting pre-commit hooks to auto-install on clone in the future' +git config --global init.templateDir ~/.git-template +pre-commit init-templatedir ~/.git-template + +echo 'installing terraform with tfenv' +tfenv install diff --git a/examples/basic/README.md b/examples/basic/README.md new file mode 100644 index 0000000..fc4ffc2 --- /dev/null +++ b/examples/basic/README.md @@ -0,0 +1,58 @@ +# basic example +A basic example for this repository + +## Code +Look to [main.tf](./main.tf), or be helpful and copy/paste that code here. + +## Applying +``` +> terraform apply + +Apply complete! Resources: 0 added, 0 changed, 0 destroyed. + +Outputs: + +example = { + "tags_module" = { + "name" = "TEST" + "name32" = "TEST" + "name6" = "TEST" + "namenosymbols" = "TEST" + "tags" = { + "Name" = "TEST" + "terraform_managed" = true + "terraform_module" = "terraform-terraform-tags-1.0.0" + "terraform_root_module" = "." + "terraform_workspace" = "default" + } + "tags_as_list_of_maps" = [ + { + "key" = "Name" + "value" = "TEST" + }, + { + "key" = "terraform_managed" + "value" = true + }, + { + "key" = "terraform_module" + "value" = "terraform-terraform-tags-1.0.0" + }, + { + "key" = "terraform_root_module" + "value" = "." + }, + { + "key" = "terraform_workspace" + "value" = "default" + }, + ] + "tags_no_name" = { + "terraform_managed" = true + "terraform_module" = "terraform-terraform-tags-1.0.0" + "terraform_root_module" = "." + "terraform_workspace" = "default" + } + } +} +``` diff --git a/examples/basic/main.tf b/examples/basic/main.tf new file mode 100644 index 0000000..13ef2c1 --- /dev/null +++ b/examples/basic/main.tf @@ -0,0 +1,10 @@ + +module "example" { + source = "../.." + + name = "test" +} + +output "example" { + value = module.example +} diff --git a/iam.tf b/iam.tf new file mode 100644 index 0000000..4d604df --- /dev/null +++ b/iam.tf @@ -0,0 +1,47 @@ +resource "aws_accessanalyzer_analyzer" "analyzer" { + count = var.enable_iam_access_analyzer ? 1 : 0 + + analyzer_name = "default-access-analyzer" + type = "ACCOUNT" + tags = local.tags +} + +resource "aws_accessanalyzer_analyzer" "analyzer_unused" { + count = var.enable_iam_access_analyzer ? 1 : 0 + + analyzer_name = "default-unused-access-analyzer" + type = "ACCOUNT_UNUSED_ACCESS" + tags = local.tags + + configuration { + unused_access { + unused_access_age = var.iam_analyzer_unused_access_age + } + } +} + +resource "aws_cloudwatch_event_rule" "analyzer" { + count = var.enable_iam_access_analyzer ? 1 : 0 + + name_prefix = substr("iam-aa-finding-rhythmic", 0, 35) + description = "Match on IAM Access Analyzer finding (Rhythmic)" + + event_pattern = <