diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md new file mode 100644 index 0000000..687d702 --- /dev/null +++ b/.chglog/CHANGELOG.tpl.md @@ -0,0 +1,111 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +{{ if .Versions -}} + +## [Unreleased] +{{ if .Unreleased.CommitGroups -}} +{{ range .Unreleased.CommitGroups -}} +### {{ .Title }} +{{ range .Commits -}} +{{/* SKIPPING RULES - START */ -}} +{{- if not (hasPrefix .Subject "Updated CHANGELOG") -}} +{{- if not (contains .Subject "[ci skip]") -}} +{{- if not (contains .Subject "[skip ci]") -}} +{{- if not (hasPrefix .Subject "Merge pull request ") -}} +{{- if not (hasPrefix .Subject "Added CHANGELOG") -}} +{{- /* SKIPPING RULES - END */ -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{/* SKIPPING RULES - START */ -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{/* SKIPPING RULES - END */ -}} +{{ end }} +{{ end -}} +{{ else }} +{{ range .Unreleased.Commits -}} +{{/* SKIPPING RULES - START */ -}} +{{- if not (hasPrefix .Subject "Updated CHANGELOG") -}} +{{- if not (contains .Subject "[ci skip]") -}} +{{- if not (contains .Subject "[skip ci]") -}} +{{- if not (hasPrefix .Subject "Merge pull request ") -}} +{{- if not (hasPrefix .Subject "Added CHANGELOG") -}} +{{- /* SKIPPING RULES - END */ -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{/* SKIPPING RULES - START */ -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{/* SKIPPING RULES - END */ -}} +{{ end }} +{{ end -}} +{{ end -}} + +{{ range .Versions }} + +## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} +{{ if .CommitGroups -}} +{{ range .CommitGroups -}} +### {{ .Title }} +{{ range .Commits -}} +{{/* SKIPPING RULES - START */ -}} +{{- if not (hasPrefix .Subject "Updated CHANGELOG") -}} +{{- if not (contains .Subject "[ci skip]") -}} +{{- if not (contains .Subject "[skip ci]") -}} +{{- if not (hasPrefix .Subject "Merge pull request ") -}} +{{- if not (hasPrefix .Subject "Added CHANGELOG") -}} +{{- /* SKIPPING RULES - END */ -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{/* SKIPPING RULES - START */ -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{/* SKIPPING RULES - END */ -}} +{{ end }} +{{ end -}} +{{ else }} +{{ range .Commits -}} +{{/* SKIPPING RULES - START */ -}} +{{- if not (hasPrefix .Subject "Updated CHANGELOG") -}} +{{- if not (contains .Subject "[ci skip]") -}} +{{- if not (contains .Subject "[skip ci]") -}} +{{- if not (hasPrefix .Subject "Merge pull request ") -}} +{{- if not (hasPrefix .Subject "Added CHANGELOG") -}} +{{- /* SKIPPING RULES - END */ -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{/* SKIPPING RULES - START */ -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{ end -}} +{{/* SKIPPING RULES - END */ -}} +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} + +{{- if .Versions }} +[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD +{{ range .Versions -}} +{{ if .Tag.Previous -}} +[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} +{{ end -}} +{{ end -}} +{{ end -}} diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100644 index 0000000..4f6bab9 --- /dev/null +++ b/.chglog/config.yml @@ -0,0 +1,11 @@ +--- +style: github +template: CHANGELOG.tpl.md +info: + title: CHANGELOG + repository_url: https://github.com/svenlito/terraform-aws-eventbridge +options: + header: + pattern: "^(.*)$" + pattern_maps: + - Subject diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..069c4d4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,32 @@ +# EditorConfig is awesome: http://EditorConfig.org +# Uses editorconfig to maintain consistent coding styles + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +max_line_length = 80 +trim_trailing_whitespace = true + +[*.{hcl}] +indent_size = 2 +indent_style = space + +[*.md] +max_line_length = 0 +trim_trailing_whitespace = false + +# Tab indentation (no size specified) +[Makefile] +tab_width = 2 +indent_style = tab + +# Don't wrap lines for Git commit messages +[COMMIT_EDITMSG] +max_line_length = 0 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000..2be2f5d --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,102 @@ +--- +name: Pre-Commit + +on: + pull_request: + push: + branches: + - master + +jobs: + # Min Terraform version(s) + getDirectories: + name: Get root directories + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Install Python + uses: actions/setup-python@v2 + - name: Build matrix + id: matrix + run: | + DIRS=$(python -c "import json; import glob; print(json.dumps([x.replace('/versions.tf', '') for x in glob.glob('./**/versions.tf', recursive=True)]))") + echo "::set-output name=directories::$DIRS" + outputs: + directories: ${{ steps.matrix.outputs.directories }} + + preCommitMinVersions: + name: Min TF validate + needs: getDirectories + runs-on: ubuntu-latest + strategy: + matrix: + directory: ${{ fromJson(needs.getDirectories.outputs.directories) }} + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Install Python + uses: actions/setup-python@v2 + - name: Terraform min/max versions + id: minMax + uses: clowdhaus/terraform-min-max@v1.0.1 + with: + directory: ${{ matrix.directory }} + - name: Install Terraform v${{ steps.minMax.outputs.minVersion }} + uses: hashicorp/setup-terraform@v1 + with: + terraform_version: ${{ steps.minMax.outputs.minVersion }} + - name: Install pre-commit dependencies + run: pip install pre-commit + - name: Execute pre-commit + # Run only validate pre-commit check on min version supported + if: ${{ matrix.directory != '.' }} + run: + pre-commit run terraform_validate --color=always --show-diff-on-failure --files ${{ matrix.directory }}/* + - name: Execute pre-commit + # Run only validate pre-commit check on min version supported + if: ${{ matrix.directory == '.' }} + run: + pre-commit run terraform_validate --color=always --show-diff-on-failure --files $(ls *.tf) + + # Max Terraform version + getBaseVersion: + name: Module max TF version + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Terraform min/max versions + id: minMax + uses: clowdhaus/terraform-min-max@v1.0.1 + outputs: + minVersion: ${{ steps.minMax.outputs.minVersion }} + maxVersion: ${{ steps.minMax.outputs.maxVersion }} + + preCommitMaxVersion: + name: Max TF pre-commit + runs-on: ubuntu-latest + needs: getBaseVersion + strategy: + fail-fast: false + matrix: + version: + - ${{ needs.getBaseVersion.outputs.maxVersion }} + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Install Python + uses: actions/setup-python@v2 + - name: Install Terraform v${{ matrix.version }} + uses: hashicorp/setup-terraform@v1 + with: + terraform_version: ${{ matrix.version }} + - name: Install pre-commit dependencies + run: | + pip install pre-commit + curl -L "$(curl -s https://api.github.com/repos/terraform-docs/terraform-docs/releases/latest | grep -o -E "https://.+?-linux-amd64" | head -n1)" > terraform-docs && chmod +x terraform-docs && sudo mv terraform-docs /usr/bin/ + curl -L "$(curl -s https://api.github.com/repos/terraform-linters/tflint/releases/latest | grep -o -E "https://.+?_linux_amd64.zip")" > tflint.zip && unzip tflint.zip && rm tflint.zip && sudo mv tflint /usr/bin/ + - name: Execute pre-commit + # Run all pre-commit checks on max version supported + if: ${{ matrix.version == needs.getBaseVersion.outputs.maxVersion }} + run: pre-commit run --color=always --show-diff-on-failure --all-files diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..627f068 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +.DS_Store + +# Local .terraform directories +**/.terraform/* + +# Terraform lockfile +.terraform.lock.hcl + +# .tfstate files +*.tfstate +*.tfstate.* +*.tfplan + +# Crash log files +crash.log + +# Exclude all .tfvars files, which are likely to contain sentitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ed7b682 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,27 @@ +--- +repos: + - repo: git://github.com/antonbabenko/pre-commit-terraform + rev: v1.48.0 + hooks: + - id: terraform_fmt + - id: terraform_validate + - id: terraform_docs + - id: terraform_tflint + args: + - '--args=--only=terraform_deprecated_interpolation' + - '--args=--only=terraform_deprecated_index' + - '--args=--only=terraform_unused_declarations' + - '--args=--only=terraform_comment_syntax' + - '--args=--only=terraform_documented_outputs' + - '--args=--only=terraform_documented_variables' + - '--args=--only=terraform_typed_variables' + - '--args=--only=terraform_module_pinned_source' + - '--args=--only=terraform_naming_convention' + - '--args=--only=terraform_required_version' + - '--args=--only=terraform_required_providers' + - '--args=--only=terraform_standard_module_structure' + - '--args=--only=terraform_workspace_remote' + - repo: git://github.com/pre-commit/pre-commit-hooks + rev: v3.4.0 + hooks: + - id: check-merge-conflict diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fe36d3a --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2021 Sven Lito + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..558dac5 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +.PHONY: changelog release + +changelog: + git-chglog -o CHANGELOG.md --next-tag `semtag final -s minor -o` + +release: + semtag final -s minor diff --git a/README.md b/README.md index 7718812..96bdc2b 100644 --- a/README.md +++ b/README.md @@ -1 +1,308 @@ -# terraform-aws-eventbridge +# AWS EventBridge Terraform module + +Terraform module to create EventBridge resources. + +The following resources are currently supported: + +* [Cloudwatch Event Archive](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_archive) +* [Cloudwatch Event Bus](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_bus) +* [Cloudwatch Event Permission](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_permission) +* [Cloudwatch Event Rule](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) +* [Cloudwatch Event Target](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) + +## Features + +- [x] Creates AWS EventBridge Resources +- [x] Support AWS EventBridge Archives and Replays +- [x] Conditional creation for many types of resources +- [x] Support IAM policy attachments and various ways to create and attach additional policies +- [ ] Support monitoring usage with Cloudwatch Metrics + +## Usage + +### EventBridge Bus + +```hcl +module "eventbridge" { + source = "" + + bus_name = "my-bus" + + tags = { + Name = "my-bus" + } +} +``` + +### EventBridge Rule + +```hcl +module "eventbridge" { + source = "" + + bus_name = "my-bus" + + create_targets = false + + rules = { + logs = { + description = "Capture log data" + event_pattern = jsonencode({ "source" : ["my.app.logs"] }) + } + } + + tags = { + Name = "my-bus" + } +} +``` + +### EventBridge Target + +```hcl +module "eventbridge" { + source = "" + + bus_name = "my-bus" + + rules = { + logs = { + description = "Capture log data" + event_pattern = jsonencode({ "source" : ["my.app.logs"] }) + } + } + + targets = { + logs = [ + { + name = "send-logs-to-sqs" + arn = aws_sqs_queue.queue.arn + }, + { + name = "send-logs-to-cloudwatch" + arn = aws_cloudwatch_log_stream.logs.arn + } + ] + } + + tags = { + Name = "my-bus" + } +} +``` + +### EventBridge Archive + +```hcl +module "eventbridge_with_archive" { + source = "" + + bus_name = "my-bus" + + create_archives = true + + archive_config = [ + { + name = "my-bus-launch-archive", + description = "EC2 AutoScaling Event archive", + retention_days = 1 + event_pattern = < 0`. + 3. `policy` - ARN of existing IAM policy, when `attach_policy = true`. + 4. `policies` - List of ARNs of existing IAM policies, when `attach_policies = true` and `number_of_policies > 0`. + 5. `policy_statements` - Map of maps to define IAM statements which will be generated as IAM policy. Requires `attach_policy_statements = true`. See `examples/complete` for more information. + +## Conditional creation + +Sometimes you need to have a way to create resources conditionally but Terraform does not allow usage of `count` inside `module` block, so the solution is to specify `create` arguments. + +```hcl +module "eventbridge" { + source = "" + + create = false # to disable all resources + + create_bus = false # to control creation of the EventBridge Bus and related resources + create_rule = false # to control creation of EventBridge Rules and related resources + create_targets = false # to control creation of EventBridge Targets and related resources + create_archives = false # to control creation of EventBridge Archives + create_permissions = false # to control creation of EventBridge Permissions + create_role = false # to control creation of the IAM role and policies required for EventBridge + + attach_kinesis_policy = false + attach_kinesis_firehose_policy = false + attach_sqs_policy = false + attach_ecs_policy = false + attach_lambda_policy = false + attach_sfn_policy = false + attach_cloudwatch_policy = false + attach_tracing_policy = false + + # ... omitted +} +``` + +## Examples + +* [Complete](/examples/complete) +* [Simple](/examples/simple) +* [Archive](/examples/with-archive) +* [Permissions](/examples/with-permissions) +* [SQS Target](/examples/sqs-target) +* [API-Gateway](/examples/api-gateway-event-source) +* [Input Transformation](/examples/transform-input) +* [Step Function Target](/examples/step-function-target) + +## Change log + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.12.26 | +| aws | >= 3.19 | + +## Providers + +| Name | Version | +|------|---------| +| aws | >= 3.19 | + +## Modules + +No Modules. + +## Resources + +| Name | +|------| +| [aws_cloudwatch_event_archive](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_archive) | +| [aws_cloudwatch_event_bus](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_bus) | +| [aws_cloudwatch_event_permission](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_permission) | +| [aws_cloudwatch_event_rule](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | +| [aws_cloudwatch_event_target](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | +| [aws_iam_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy) | +| [aws_iam_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | +| [aws_iam_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | +| [aws_iam_policy_document](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | +| [aws_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | +| [aws_iam_role_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| archive\_config | A list of objects with the EventBridge Archive definitions. | `list(any)` | `[]` | no | +| attach\_cloudwatch\_policy | Controls whether the Cloudwatch policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| attach\_ecs\_policy | Controls whether the ECS policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| attach\_kinesis\_firehose\_policy | Controls whether the Kinesis Firehose policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| attach\_kinesis\_policy | Controls whether the Kinesis policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| attach\_lambda\_policy | Controls whether the Lambda Function policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| attach\_policies | Controls whether list of policies should be added to IAM role | `bool` | `false` | no | +| attach\_policy | Controls whether policy should be added to IAM role | `bool` | `false` | no | +| attach\_policy\_json | Controls whether policy\_json should be added to IAM role | `bool` | `false` | no | +| attach\_policy\_jsons | Controls whether policy\_jsons should be added to IAM role | `bool` | `false` | no | +| attach\_policy\_statements | Controls whether policy\_statements should be added to IAM role | `bool` | `false` | no | +| attach\_sfn\_policy | Controls whether the StepFunction policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| attach\_sqs\_policy | Controls whether the SQS policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| attach\_tracing\_policy | Controls whether X-Ray tracing policy should be added to IAM role for EventBridge | `bool` | `false` | no | +| bus\_name | A unique name for your EventBridge Bus | `string` | `""` | no | +| cloudwatch\_target\_arns | The Amazon Resource Name (ARN) of the Cloudwatch Log Streams you want to use as EventBridge targets | `list(string)` | `[]` | no | +| create | Controls whether resources should be created | `bool` | `true` | no | +| create\_archives | Controls whether EventBridge Archive resources should be created | `bool` | `false` | no | +| create\_bus | Controls whether EventBridge Bus resource should be created | `bool` | `true` | no | +| create\_permissions | Controls whether EventBridge Permission resources should be created | `bool` | `true` | no | +| create\_role | Controls whether IAM role for Lambda Function should be created | `bool` | `true` | no | +| create\_rules | Controls whether EventBridge Rule resources should be created | `bool` | `true` | no | +| create\_targets | Controls whether EventBridge Target resources should be created | `bool` | `true` | no | +| ecs\_target\_arns | The Amazon Resource Name (ARN) of the AWS ECS Tasks you want to use as EventBridge targets | `list(string)` | `[]` | no | +| kinesis\_firehose\_target\_arns | The Amazon Resource Name (ARN) of the Kinesis Firehose Delivery Streams you want to use as EventBridge targets | `list(string)` | `[]` | no | +| kinesis\_target\_arns | The Amazon Resource Name (ARN) of the Kinesis Streams you want to use as EventBridge targets | `list(string)` | `[]` | no | +| lambda\_target\_arns | The Amazon Resource Name (ARN) of the Lambda Functions you want to use as EventBridge targets | `list(string)` | `[]` | no | +| number\_of\_policies | Number of policies to attach to IAM role | `number` | `0` | no | +| number\_of\_policy\_jsons | Number of policies JSON to attach to IAM role | `number` | `0` | no | +| permission\_config | A list of objects with EventBridge Permission definitions. | `list(any)` | `[]` | no | +| policies | List of policy statements ARN to attach to IAM role | `list(string)` | `[]` | no | +| policy | An additional policy document ARN to attach to IAM role | `string` | `null` | no | +| policy\_json | An additional policy document as JSON to attach to IAM role | `string` | `null` | no | +| policy\_jsons | List of additional policy documents as JSON to attach to IAM role | `list(string)` | `[]` | no | +| policy\_statements | Map of dynamic policy statements to attach to IAM role | `any` | `{}` | no | +| role\_description | Description of IAM role to use for Lambda Function | `string` | `null` | no | +| role\_force\_detach\_policies | Specifies to force detaching any policies the IAM role has before destroying it. | `bool` | `true` | no | +| role\_name | Name of IAM role to use for Lambda Function | `string` | `null` | no | +| role\_path | Path of IAM role to use for Lambda Function | `string` | `null` | no | +| role\_permissions\_boundary | The ARN of the policy that is used to set the permissions boundary for the IAM role used by Lambda Function | `string` | `null` | no | +| role\_tags | A map of tags to assign to IAM role | `map(string)` | `{}` | no | +| rules | A map of objects with EventBridge Rule definitions. | `map(any)` | `{}` | no | +| sfn\_target\_arns | The Amazon Resource Name (ARN) of the StepFunctions you want to use as EventBridge targets | `list(string)` | `[]` | no | +| sqs\_target\_arns | The Amazon Resource Name (ARN) of the AWS SQS Queues you want to use as EventBridge targets | `list(string)` | `[]` | no | +| tags | A map of tags to assign to resources. | `map(string)` | `{}` | no | +| targets | A Map of objects with EventBridge Target definitions. | `any` | `{}` | no | +| trusted\_entities | Step Function additional trusted entities for assuming roles (trust relationship) | `list(string)` | `[]` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| eventbridge\_role\_arn | The ARN of the IAM role created for EventBridge | +| eventbridge\_role\_name | The name of the IAM role created for EventBridge | +| this\_eventbridge\_archive\_arns | The EventBridge Archive Arns created | +| this\_eventbridge\_bus\_arn | The EventBridge Bus Arn | +| this\_eventbridge\_bus\_name | The EventBridge Bus Name | +| this\_eventbridge\_permission\_ids | The EventBridge Permission Arns created | +| this\_eventbridge\_rule\_arns | The EventBridge Rule ARNs created | +| this\_eventbridge\_rule\_ids | The EventBridge Rule IDs created | + + +## Authors + +Module managed by [Sven Lito](https://github.com/svenlito). Check out [serverless.tf](https://serverless.tf) to learn more about doing serverless with Terraform. + +## License + +Apache 2 Licensed. See LICENSE for full details. diff --git a/examples/api-gateway-event-source/README.md b/examples/api-gateway-event-source/README.md new file mode 100644 index 0000000..39ae696 --- /dev/null +++ b/examples/api-gateway-event-source/README.md @@ -0,0 +1,16 @@ +# EventBridge API Gateway Event Source + +Configuration in this directory creates EventBridge resource configuration including an API Gateway and a SQS queue. + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. + diff --git a/examples/api-gateway-event-source/main.tf b/examples/api-gateway-event-source/main.tf new file mode 100644 index 0000000..8e939ee --- /dev/null +++ b/examples/api-gateway-event-source/main.tf @@ -0,0 +1,158 @@ +terraform { + required_version = ">= 0.14.0" + + required_providers { + aws = ">= 3.19" + random = ">= 0" + } +} + +provider "aws" { + region = "ap-southeast-1" + + # Make it faster by skipping something + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +module "eventbridge" { + source = "../../" + + bus_name = "${random_pet.this.id}-bus" + + attach_sqs_policy = true + sqs_target_arns = [ + aws_sqs_queue.queue.arn, + aws_sqs_queue.dlq.arn + ] + + rules = { + orders_create = { + description = "Capture all created orders", + event_pattern = jsonencode({ + "detail-type" : ["Order Create"], + "source" : ["api.gateway.orders.create"] + }) + } + } + + targets = { + orders_create = [ + { + name = "send-orders-to-sqs" + arn = aws_sqs_queue.queue.arn + dead_letter_arn = aws_sqs_queue.dlq.arn + target_id = "send-orders-to-sqs" + } + ] + } + + tags = { + Name = "${random_pet.this.id}-bus" + } +} + + +################## +# Extra resources +################## + +resource "random_pet" "this" { + length = 2 +} + +module "api_gateway" { + source = "terraform-aws-modules/apigateway-v2/aws" + version = "0.14.0" + + name = "${random_pet.this.id}-http" + description = "My ${random_pet.this.id} HTTP API Gateway" + protocol_type = "HTTP" + + create_api_domain_name = false + + integrations = { + "POST /orders/create" = { + integration_type = "AWS_PROXY" + integration_subtype = "EventBridge-PutEvents" + credentials_arn = module.apigateway_put_events_to_eventbridge_role.this_iam_role_arn + + request_parameters = jsonencode({ + EventBusName = module.eventbridge.this_eventbridge_bus_name, + Source = "api.gateway.orders.create", + DetailType = "Order Create", + Detail = "$request.body", + Time = "$context.requestTimeEpoch" + }) + + payload_format_version = "1.0" + } + } +} + +module "apigateway_put_events_to_eventbridge_role" { + source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role" + version = "3.13.0" + + create_role = true + + role_name = "apigateway-put-events-to-eventbridge" + role_requires_mfa = false + + trusted_role_services = [ + "apigateway.amazonaws.com" + ] + + custom_role_policy_arns = [ + module.apigateway_put_events_to_eventbridge_policy.arn + ] +} + +module "apigateway_put_events_to_eventbridge_policy" { + source = "terraform-aws-modules/iam/aws//modules/iam-policy" + version = "3.13.0" + + name = "apigateway-put-events-to-eventbridge" + path = "/" + description = "Allow PutEvents to EventBridge" + + policy = data.aws_iam_policy_document.apigateway_put_events_to_eventbridge_policy.json +} + +data "aws_iam_policy_document" "apigateway_put_events_to_eventbridge_policy" { + statement { + sid = "AllowPutEvents" + actions = ["events:PutEvents"] + resources = [module.eventbridge.this_eventbridge_bus_arn] + } + + depends_on = [module.eventbridge] +} + +resource "aws_sqs_queue" "dlq" { + name = "${random_pet.this.id}-dlq" +} + +resource "aws_sqs_queue" "queue" { + name = random_pet.this.id +} + +resource "aws_sqs_queue_policy" "queue" { + queue_url = aws_sqs_queue.queue.id + policy = data.aws_iam_policy_document.queue.json +} + +data "aws_iam_policy_document" "queue" { + statement { + sid = "AllowSendMessage" + actions = ["sqs:SendMessage"] + principals { + type = "Service" + identifiers = ["events.amazonaws.com"] + } + resources = [aws_sqs_queue.queue.arn] + } +} diff --git a/examples/api-gateway-event-source/outputs.tf b/examples/api-gateway-event-source/outputs.tf new file mode 100644 index 0000000..10f1f4e --- /dev/null +++ b/examples/api-gateway-event-source/outputs.tf @@ -0,0 +1,28 @@ +output "this_eventbridge_bus_name" { + description = "The EventBridge Bus Name" + value = module.eventbridge.this_eventbridge_bus_name +} + +output "this_eventbridge_bus_arn" { + description = "The EventBridge Bus Arn" + value = module.eventbridge.this_eventbridge_bus_arn +} +output "this_eventbridge_rule_ids" { + description = "The EventBridge Rule IDs created" + value = module.eventbridge.this_eventbridge_rule_ids +} + +output "this_eventbridge_rule_arns" { + description = "The EventBridge Rule ARNs created" + value = module.eventbridge.this_eventbridge_rule_arns +} + +output "eventbridge_role_arn" { + description = "The ARN of the IAM role created for EventBridge" + value = module.eventbridge.eventbridge_role_arn +} + +output "eventbridge_role_name" { + description = "The name of the IAM role created for EventBridge" + value = module.eventbridge.eventbridge_role_name +} diff --git a/examples/api-gateway-event-source/sample-order-data.json b/examples/api-gateway-event-source/sample-order-data.json new file mode 100644 index 0000000..4de316c --- /dev/null +++ b/examples/api-gateway-event-source/sample-order-data.json @@ -0,0 +1,39 @@ +{ + "data": { + "destination": { + "name": "accountName" + }, + "orderData": { + "sourceOrderId": "1234512345", + "items": [ + { + "sku": "Business Cards", + "sourceItemId": "1234512346", + "components": [ + { + "code": "Content", + "fetch": true, + "path": "http://www.w2psite.com/businessCard.pdf" + } + ] + } + ], + "shipments": [ + { + "shipTo": { + "name": "John Doe", + "companyName": "Acme", + "address1": "1234 Main St.", + "town": "Capitol", + "postcode": "12345", + "isoCountry": "US" + }, + "carrier":{ + "code": "fedex", + "service": "ground" + } + } + ] + } + } +} diff --git a/examples/api-gateway-event-source/variables.tf b/examples/api-gateway-event-source/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/examples/cloudwatch-target/README.md b/examples/cloudwatch-target/README.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/cloudwatch-target/main.tf b/examples/cloudwatch-target/main.tf new file mode 100644 index 0000000..3ba6bb5 --- /dev/null +++ b/examples/cloudwatch-target/main.tf @@ -0,0 +1,68 @@ +terraform { + required_version = ">= 0.14.0" + + required_providers { + aws = ">= 3.19" + random = ">= 0" + } +} + +provider "aws" { + region = "ap-southeast-1" + + # Make it faster by skipping something + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +module "eventbridge" { + source = "../../" + + bus_name = "${random_pet.this.id}-bus" + + attach_cloudwatch_policy = true + + cloudwatch_target_arns = [ + aws_cloudwatch_log_group.this.arn + ] + + rules = { + orders = { + description = "Capture all created orders", + event_pattern = jsonencode({ "source" : ["orders.create"] }) + } + } + + targets = { + orders = [ + { + name = "log-orders-to-cloudwatch" + arn = aws_cloudwatch_log_group.this.arn + } + ] + } + + tags = { + Name = "${random_pet.this.id}-bus" + } +} + +################## +# Extra resources +################## + +resource "random_pet" "this" { + length = 2 +} + +resource "aws_cloudwatch_log_group" "this" { + name = "/aws/events/${random_pet.this.id}" + + tags = { + Name = "${random_pet.this.id}-log-group" + } +} + diff --git a/examples/cloudwatch-target/outputs.tf b/examples/cloudwatch-target/outputs.tf new file mode 100644 index 0000000..7a3ecdc --- /dev/null +++ b/examples/cloudwatch-target/outputs.tf @@ -0,0 +1,5 @@ +output "eventbridge_bus_arn" { + description = "The EventBridge Bus ARN" + value = module.eventbridge.this_eventbridge_bus_arn +} + diff --git a/examples/cloudwatch-target/variables.tf b/examples/cloudwatch-target/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/examples/complete/README.md b/examples/complete/README.md new file mode 100644 index 0000000..9c16b08 --- /dev/null +++ b/examples/complete/README.md @@ -0,0 +1,15 @@ +# EventBridge Complete Example + +Configuration in this directory creates EventBridge resource configuration including an SQS queue, Kinesis stream, and DynamoDB table. + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. diff --git a/examples/complete/main.tf b/examples/complete/main.tf new file mode 100644 index 0000000..6b0f193 --- /dev/null +++ b/examples/complete/main.tf @@ -0,0 +1,221 @@ +terraform { + required_version = ">= 0.14.0" + + required_providers { + aws = ">= 3.19" + random = ">= 0" + } +} + +provider "aws" { + region = "ap-southeast-1" + + # Make it faster by skipping something + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +resource "random_pet" "this" { + length = 2 +} + +module "eventbridge" { + source = "../../" + + bus_name = "${random_pet.this.id}-bus" + + create_bus = true + create_rules = true + create_targets = true + create_archives = true + create_permissions = true + + attach_tracing_policy = true + attach_kinesis_policy = true + attach_kinesis_firehose_policy = true + attach_sqs_policy = true + attach_ecs_policy = true + attach_lambda_policy = true + attach_sfn_policy = true + attach_cloudwatch_policy = true + + sqs_target_arns = [aws_sqs_queue.queue.arn] + ecs_target_arns = [] + kinesis_target_arns = [aws_kinesis_stream.this.arn] + kinesis_firehose_target_arns = [] + lambda_target_arns = [] + sfn_target_arns = [] + cloudwatch_target_arns = [aws_cloudwatch_log_group.this.arn] + + permission_config = [ + { + account_id = "099720109477", + statement_id = "canonical" + }, + { + account_id = "099720109466", + statement_id = "canonical_two" + } + ] + + archive_config = [ + { + description = "some archive" + retention_days = 1 + event_pattern = < + } + EOF + } +} + +################## +# Extra resources +################## + +resource "aws_kinesis_stream" "this" { + name = random_pet.this.id + shard_count = 1 +} + +resource "aws_sqs_queue" "queue" { + name = "${random_pet.this.id}-queue" +} + +resource "aws_sqs_queue" "dlq" { + name = "${random_pet.this.id}-dlq" +} + +resource "aws_sqs_queue_policy" "queue" { + queue_url = aws_sqs_queue.queue.id + policy = data.aws_iam_policy_document.queue.json +} + +data "aws_iam_policy_document" "queue" { + statement { + sid = "events-policy" + actions = ["sqs:SendMessage"] + principals { + type = "Service" + identifiers = ["events.amazonaws.com"] + } + resources = [aws_sqs_queue.queue.arn] + } +} + +resource "aws_cloudwatch_log_group" "this" { + name = "/aws/events/${random_pet.this.id}" + + tags = { + Name = "${random_pet.this.id}-log-group" + } +} + diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf new file mode 100644 index 0000000..4b50256 --- /dev/null +++ b/examples/complete/outputs.tf @@ -0,0 +1,14 @@ +output "eventbridge_bus_arn" { + description = "The EventBridge Bus ARN" + value = module.eventbridge.this_eventbridge_bus_arn +} + +output "eventbridge_rule_ids" { + description = "The EventBridge Rule IDs" + value = module.eventbridge.this_eventbridge_rule_ids +} + +output "eventbridge_rule_arns" { + description = "The EventBridge Rule ARNs" + value = module.eventbridge.this_eventbridge_rule_arns +} diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/examples/simple/README.md b/examples/simple/README.md new file mode 100644 index 0000000..1d4cc2a --- /dev/null +++ b/examples/simple/README.md @@ -0,0 +1,16 @@ +# EventBridge Simple Example + +Configuration in this directory creates EventBridge resource configuration. + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. + diff --git a/examples/simple/main.tf b/examples/simple/main.tf new file mode 100644 index 0000000..e2dfbb2 --- /dev/null +++ b/examples/simple/main.tf @@ -0,0 +1,34 @@ +terraform { + required_version = ">= 0.14.0" + + required_providers { + aws = ">= 3.19" + random = ">= 0" + } +} + +provider "aws" { + region = "ap-southeast-1" + + # Make it faster by skipping something + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +resource "random_pet" "this" { + length = 2 +} + +module "eventbridge" { + source = "../../" + + bus_name = "${random_pet.this.id}-bus" + + tags = { + Name = "${random_pet.this.id}-bus" + } +} + diff --git a/examples/simple/outputs.tf b/examples/simple/outputs.tf new file mode 100644 index 0000000..7a3ecdc --- /dev/null +++ b/examples/simple/outputs.tf @@ -0,0 +1,5 @@ +output "eventbridge_bus_arn" { + description = "The EventBridge Bus ARN" + value = module.eventbridge.this_eventbridge_bus_arn +} + diff --git a/examples/simple/variables.tf b/examples/simple/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/examples/sqs-target/README.md b/examples/sqs-target/README.md new file mode 100644 index 0000000..96fcf85 --- /dev/null +++ b/examples/sqs-target/README.md @@ -0,0 +1,17 @@ +# EventBridge SQS Example + +Configuration in this directory creates EventBridge resource configuration. + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. + + diff --git a/examples/sqs-target/main.tf b/examples/sqs-target/main.tf new file mode 100644 index 0000000..a5afedb --- /dev/null +++ b/examples/sqs-target/main.tf @@ -0,0 +1,115 @@ +terraform { + required_version = ">= 0.14.0" + + required_providers { + aws = ">= 3.19" + random = ">= 0" + } +} + +provider "aws" { + region = "ap-southeast-1" + + # Make it faster by skipping something + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +module "eventbridge" { + source = "../../" + + bus_name = "${random_pet.this.id}-bus" + + attach_sqs_policy = true + sqs_target_arns = [ + aws_sqs_queue.queue.arn, + aws_sqs_queue.fifo.arn, + aws_sqs_queue.dlq.arn + ] + + rules = { + orders = { + description = "Capture all created orders", + event_pattern = jsonencode({ "source" : ["orders.create"] }) + } + } + + targets = { + orders = [ + { + name = "send-orders-to-sqs" + arn = aws_sqs_queue.queue.arn + }, + { + name = "send-orders-to-sqs-wth-dead-letter" + arn = aws_sqs_queue.queue.arn + dead_letter_arn = aws_sqs_queue.dlq.arn + }, + { + name = "send-orders-to-sqs-with-retry-policy" + arn = aws_sqs_queue.queue.arn + dead_letter_arn = aws_sqs_queue.dlq.arn + retry_policy = { + maximum_retry_attempts = 10 + maximum_event_age_in_seconds = 300 + } + }, + { + name = "send-orders-to-fifo-sqs" + arn = aws_sqs_queue.fifo.arn + dead_letter_arn = aws_sqs_queue.dlq.arn + message_group_id = "send-orders-to-fifo-sqs" + } + ] + } + + tags = { + Name = "${random_pet.this.id}-bus" + } +} + +################## +# Extra resources +################## + +resource "random_pet" "this" { + length = 2 +} + +resource "aws_sqs_queue" "queue" { + name = random_pet.this.id +} + +resource "aws_sqs_queue" "fifo" { + name = "${random_pet.this.id}.fifo" + fifo_queue = true + content_based_deduplication = true +} + +resource "aws_sqs_queue" "dlq" { + name = "${random_pet.this.id}-dlq" +} + +resource "aws_sqs_queue_policy" "queue" { + queue_url = aws_sqs_queue.queue.id + policy = data.aws_iam_policy_document.queue.json +} + +data "aws_iam_policy_document" "queue" { + statement { + sid = "events-policy" + actions = ["sqs:SendMessage"] + principals { + type = "Service" + identifiers = ["events.amazonaws.com"] + } + resources = [ + aws_sqs_queue.queue.arn, + aws_sqs_queue.fifo.arn + ] + } +} + diff --git a/examples/sqs-target/outputs.tf b/examples/sqs-target/outputs.tf new file mode 100644 index 0000000..4b50256 --- /dev/null +++ b/examples/sqs-target/outputs.tf @@ -0,0 +1,14 @@ +output "eventbridge_bus_arn" { + description = "The EventBridge Bus ARN" + value = module.eventbridge.this_eventbridge_bus_arn +} + +output "eventbridge_rule_ids" { + description = "The EventBridge Rule IDs" + value = module.eventbridge.this_eventbridge_rule_ids +} + +output "eventbridge_rule_arns" { + description = "The EventBridge Rule ARNs" + value = module.eventbridge.this_eventbridge_rule_arns +} diff --git a/examples/sqs-target/variables.tf b/examples/sqs-target/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/examples/step-function-target/README.md b/examples/step-function-target/README.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/step-function-target/main.tf b/examples/step-function-target/main.tf new file mode 100644 index 0000000..dc694b0 --- /dev/null +++ b/examples/step-function-target/main.tf @@ -0,0 +1,79 @@ +terraform { + required_version = ">= 0.14.0" + + required_providers { + aws = ">= 3.19" + random = ">= 0" + } +} + +provider "aws" { + region = "ap-southeast-1" + + # Make it faster by skipping something + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +module "eventbridge" { + source = "../../" + + bus_name = "${random_pet.this.id}-bus" + + attach_sfn_policy = true + sfn_target_arns = [module.step_function.this_state_machine_arn] + + rules = { + orders = { + description = "Capture order data" + event_pattern = jsonencode({ "source" : ["orders.create"] }) + } + } + + targets = { + orders = [ + { + name = "process-order-with-sfn" + arn = module.step_function.this_state_machine_arn + attach_role_arn = true + } + ] + } + + tags = { + Name = "${random_pet.this.id}-bus" + } +} + +################## +# Extra resources +################## + +resource "random_pet" "this" { + length = 2 +} + +module "step_function" { + source = "terraform-aws-modules/step-functions/aws" + version = "1.2.0" + + name = random_pet.this.id + + definition = jsonencode(yamldecode(templatefile("sfn.asl.yaml", {}))) + + trusted_entities = ["events.amazonaws.com"] + + service_integrations = { + stepfunction = { + stepfunction = ["*"] + } + } + + tags = { + Name = "${random_pet.this.id}-step-function" + } +} + diff --git a/examples/step-function-target/outputs.tf b/examples/step-function-target/outputs.tf new file mode 100644 index 0000000..7a3ecdc --- /dev/null +++ b/examples/step-function-target/outputs.tf @@ -0,0 +1,5 @@ +output "eventbridge_bus_arn" { + description = "The EventBridge Bus ARN" + value = module.eventbridge.this_eventbridge_bus_arn +} + diff --git a/examples/step-function-target/sfn.asl.yaml b/examples/step-function-target/sfn.asl.yaml new file mode 100644 index 0000000..dfc0c19 --- /dev/null +++ b/examples/step-function-target/sfn.asl.yaml @@ -0,0 +1,12 @@ +--- +Comment: Default Step Function +StartAt: Hello +States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true diff --git a/examples/step-function-target/variables.tf b/examples/step-function-target/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/examples/transform-input/README.md b/examples/transform-input/README.md new file mode 100644 index 0000000..2fb4520 --- /dev/null +++ b/examples/transform-input/README.md @@ -0,0 +1,17 @@ +# EventBridge Input Transform Example + +Configuration in this directory creates EventBridge resource configuration. + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. + + diff --git a/examples/transform-input/main.tf b/examples/transform-input/main.tf new file mode 100644 index 0000000..6c6547f --- /dev/null +++ b/examples/transform-input/main.tf @@ -0,0 +1,84 @@ +terraform { + required_version = ">= 0.14.0" + + required_providers { + aws = ">= 3.19" + random = ">= 0" + } +} + +provider "aws" { + region = "ap-southeast-1" + + # Make it faster by skipping something + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +module "eventbridge" { + source = "../../" + + bus_name = "${random_pet.this.id}-bus" + + rules = { + orders = { + description = "Capture all order data" + event_pattern = jsonencode({ "source" : ["orders.create"] }) + } + } + + targets = { + orders = [ + { + name = "send-orders-to-sqs" + arn = aws_sqs_queue.queue.arn + input_transformer = { + input_paths = { + order_id = "$.detail.order_id" + } + input_template = < + } + EOF + } + } + ] + } + + tags = { + Name = "${random_pet.this.id}-bus" + } +} + +################## +# Extra resources +################## + +resource "random_pet" "this" { + length = 2 +} + +resource "aws_sqs_queue" "queue" { + name = "${random_pet.this.id}-queue" +} + +resource "aws_sqs_queue_policy" "queue" { + queue_url = aws_sqs_queue.queue.id + policy = data.aws_iam_policy_document.queue.json +} + +data "aws_iam_policy_document" "queue" { + statement { + sid = "events-policy" + actions = ["sqs:SendMessage"] + principals { + type = "Service" + identifiers = ["events.amazonaws.com"] + } + resources = [aws_sqs_queue.queue.arn] + } +} diff --git a/examples/transform-input/outputs.tf b/examples/transform-input/outputs.tf new file mode 100644 index 0000000..7a3ecdc --- /dev/null +++ b/examples/transform-input/outputs.tf @@ -0,0 +1,5 @@ +output "eventbridge_bus_arn" { + description = "The EventBridge Bus ARN" + value = module.eventbridge.this_eventbridge_bus_arn +} + diff --git a/examples/transform-input/variables.tf b/examples/transform-input/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/examples/with-archive/README.md b/examples/with-archive/README.md new file mode 100644 index 0000000..1d4cc2a --- /dev/null +++ b/examples/with-archive/README.md @@ -0,0 +1,16 @@ +# EventBridge Simple Example + +Configuration in this directory creates EventBridge resource configuration. + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. + diff --git a/examples/with-archive/main.tf b/examples/with-archive/main.tf new file mode 100644 index 0000000..2388b31 --- /dev/null +++ b/examples/with-archive/main.tf @@ -0,0 +1,100 @@ +terraform { + required_version = ">= 0.14.0" + + required_providers { + aws = ">= 3.19" + random = ">= 0" + } +} + +provider "aws" { + region = "ap-southeast-1" + + # Make it faster by skipping something + skip_get_ec2_platforms = true + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true + skip_requesting_account_id = true +} + +resource "random_pet" "this" { + length = 2 +} + +module "eventbridge" { + source = "../../" + + create_archives = true + + archive_config = [ + { + name = "${random_pet.this.id}-launch-archive", + description = "${random_pet.this.id}-launch-archive", + retention_days = 1 + event_pattern = < rule + } : {} + + name = "${replace(each.value.name, "_", "-")}-rule" + + event_bus_name = aws_cloudwatch_event_bus.this[0].name + + description = lookup(each.value, "description", null) + name_prefix = lookup(each.value, "name_prefix", null) + is_enabled = lookup(each.value, "enabled", true) + event_pattern = lookup(each.value, "event_pattern", null) + schedule_expression = lookup(each.value, "schedule_expression", null) + role_arn = aws_iam_role.eventbridge[0].arn + + tags = merge(var.tags, { + Name = "${replace(each.value.name, "_", "-")}-rule" + }) +} + +resource "aws_cloudwatch_event_target" "this" { + for_each = var.create && var.create_targets ? { + for target in local.eventbridge_targets : target.name => target + } : tomap({}) + + event_bus_name = aws_cloudwatch_event_bus.this[0].name + + rule = "${replace(each.value.rule, "_", "-")}-rule" + arn = each.value.arn + + role_arn = lookup(each.value, "attach_role_arn", null) != null ? aws_iam_role.eventbridge[0].arn : null + target_id = lookup(each.value, "target_id", null) + input = lookup(each.value, "input", null) + input_path = lookup(each.value, "input_path", null) + + dynamic "run_command_targets" { + for_each = lookup(each.value, "run_command_targets", null) != null ? [true] : [] + + content { + key = run_command_targets.value.key + values = run_command_targets.value.values + } + } + + dynamic "ecs_target" { + for_each = lookup(each.value, "ecs_target", null) != null ? [true] : [] + + content { + group = lookup(ecs_target.value, "group", null) + launch_type = lookup(ecs_target.value, "launch_type", null) + platform_version = lookup(ecs_target.value, "platform_version", null) + task_count = lookup(ecs_target.value, "task_count", null) + task_definition_arn = ecs_target.value.task_definition_arn + + dynamic "network_configuration" { + for_each = lookup(ecs_target.value, "network_configuration", null) != null ? [true] : [] + + content { + subnets = network_configuration.value.subnets + security_groups = lookup(network_configuration.value, "security_groups", null) + assign_public_ip = lookup(network_configuration.value, "assign_public_ip", null) + } + } + } + } + + dynamic "batch_target" { + for_each = lookup(each.value, "batch_target", null) != null ? [true] : [] + + content { + job_definition = batch_target.value.job_definition + job_name = batch_target.value.job_name + array_size = lookup(batch_target.value, "array_size", null) + job_attempts = lookup(batch_target.value, "job_attempts", null) + } + } + + dynamic "kinesis_target" { + for_each = lookup(each.value, "kinesis_target", null) != null ? [true] : [] + + content { + partition_key_path = lookup(kinesis_target.value, "partition_key_path", null) + } + } + + dynamic "sqs_target" { + for_each = lookup(each.value, "message_group_id", null) != null ? [true] : [] + + content { + message_group_id = each.value.message_group_id + } + } + + dynamic "input_transformer" { + for_each = lookup(each.value, "input_transformer", null) != null ? [ + each.value.input_transformer + ] : [] + + content { + input_paths = input_transformer.value.input_paths + input_template = input_transformer.value.input_template + } + } + + dynamic "dead_letter_config" { + for_each = lookup(each.value, "dead_letter_arn", null) != null ? [true] : [] + + content { + arn = each.value.dead_letter_arn + } + } + + dynamic "retry_policy" { + for_each = lookup(each.value, "retry_policy", null) != null ? [ + each.value.retry_policy + ] : [] + + content { + maximum_event_age_in_seconds = retry_policy.value.maximum_event_age_in_seconds + maximum_retry_attempts = retry_policy.value.maximum_retry_attempts + } + } +} + +resource "aws_cloudwatch_event_archive" "this" { + for_each = var.create && var.create_archives ? { + for k, v in var.archive_config : k => v + } : {} + + name = each.value.name + event_source_arn = lookup(each.value, "event_source_arn", null) == null ? aws_cloudwatch_event_bus.this[0].arn : null + description = lookup(each.value, "description", null) + event_pattern = lookup(each.value, "event_pattern", null) + retention_days = lookup(each.value, "retention_days", null) +} + +resource "aws_cloudwatch_event_permission" "this" { + for_each = var.create && var.create_permissions ? { + for permission in var.permission_config : permission.statement_id => permission + } : {} + + principal = each.value.account_id + statement_id = each.value.statement_id + event_bus_name = lookup(each.value, aws_cloudwatch_event_bus.this[0].name, null) == null ? aws_cloudwatch_event_bus.this[0].name : null +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..568855d --- /dev/null +++ b/outputs.tf @@ -0,0 +1,48 @@ +# EventBridge Bus +output "this_eventbridge_bus_name" { + description = "The EventBridge Bus Name" + value = var.bus_name +} + +output "this_eventbridge_bus_arn" { + description = "The EventBridge Bus Arn" + value = element(concat(aws_cloudwatch_event_bus.this.*.arn, [""]), 0) +} + +# EventBridge Archive +output "this_eventbridge_archive_arns" { + description = "The EventBridge Archive Arns created" + value = { for v in aws_cloudwatch_event_archive.this : v.name => v.arn } +} + +# EventBridge Permission +output "this_eventbridge_permission_ids" { + description = "The EventBridge Permission Arns created" + value = { for k, v in aws_cloudwatch_event_permission.this : k => v.id } +} + +# EventBridge Rule +output "this_eventbridge_rule_ids" { + description = "The EventBridge Rule IDs created" + value = { + for p in sort(keys(var.rules)) : p => aws_cloudwatch_event_rule.this[p].id + } +} + +output "this_eventbridge_rule_arns" { + description = "The EventBridge Rule ARNs created" + value = { + for p in sort(keys(var.rules)) : p => aws_cloudwatch_event_rule.this[p].arn + } +} + +# IAM Role +output "eventbridge_role_arn" { + description = "The ARN of the IAM role created for EventBridge" + value = element(concat(aws_iam_role.eventbridge.*.arn, [""]), 0) +} + +output "eventbridge_role_name" { + description = "The name of the IAM role created for EventBridge" + value = element(concat(aws_iam_role.eventbridge.*.name, [""]), 0) +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..42ba02d --- /dev/null +++ b/variables.tf @@ -0,0 +1,293 @@ +variable "bus_name" { + description = "A unique name for your EventBridge Bus" + type = string + default = "" +} + +variable "rules" { + description = "A map of objects with EventBridge Rule definitions." + type = map(any) + default = {} +} + +variable "targets" { + description = "A Map of objects with EventBridge Target definitions." + type = any + default = {} +} + +variable "archive_config" { + description = "A list of objects with the EventBridge Archive definitions." + type = list(any) + default = [] +} + +variable "permission_config" { + description = "A list of objects with EventBridge Permission definitions." + type = list(any) + default = [] +} + +variable "tags" { + description = "A map of tags to assign to resources." + type = map(string) + default = {} +} + +variable "create" { + description = "Controls whether resources should be created" + type = bool + default = true +} + +variable "create_role" { + description = "Controls whether IAM role for Lambda Function should be created" + type = bool + default = true +} + +variable "create_bus" { + description = "Controls whether EventBridge Bus resource should be created" + type = bool + default = true +} + +variable "create_rules" { + description = "Controls whether EventBridge Rule resources should be created" + type = bool + default = true +} + +variable "create_targets" { + description = "Controls whether EventBridge Target resources should be created" + type = bool + default = true +} + +variable "create_permissions" { + description = "Controls whether EventBridge Permission resources should be created" + type = bool + default = true +} + +variable "create_archives" { + description = "Controls whether EventBridge Archive resources should be created" + type = bool + default = false +} + +###### +# IAM +###### + +variable "role_name" { + description = "Name of IAM role to use for Lambda Function" + type = string + default = null +} + +variable "role_description" { + description = "Description of IAM role to use for Lambda Function" + type = string + default = null +} + +variable "role_path" { + description = "Path of IAM role to use for Lambda Function" + type = string + default = null +} + +variable "role_force_detach_policies" { + description = "Specifies to force detaching any policies the IAM role has before destroying it." + type = bool + default = true +} + +variable "role_permissions_boundary" { + description = "The ARN of the policy that is used to set the permissions boundary for the IAM role used by Lambda Function" + type = string + default = null +} + +variable "role_tags" { + description = "A map of tags to assign to IAM role" + type = map(string) + default = {} +} + +########### +# Policies +########### + +variable "attach_kinesis_policy" { + description = "Controls whether the Kinesis policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_kinesis_firehose_policy" { + description = "Controls whether the Kinesis Firehose policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_sqs_policy" { + description = "Controls whether the SQS policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_ecs_policy" { + description = "Controls whether the ECS policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_lambda_policy" { + description = "Controls whether the Lambda Function policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_sfn_policy" { + description = "Controls whether the StepFunction policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_cloudwatch_policy" { + description = "Controls whether the Cloudwatch policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_tracing_policy" { + description = "Controls whether X-Ray tracing policy should be added to IAM role for EventBridge" + type = bool + default = false +} + +variable "kinesis_target_arns" { + description = "The Amazon Resource Name (ARN) of the Kinesis Streams you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "kinesis_firehose_target_arns" { + description = "The Amazon Resource Name (ARN) of the Kinesis Firehose Delivery Streams you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "sqs_target_arns" { + description = "The Amazon Resource Name (ARN) of the AWS SQS Queues you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "ecs_target_arns" { + description = "The Amazon Resource Name (ARN) of the AWS ECS Tasks you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "lambda_target_arns" { + description = "The Amazon Resource Name (ARN) of the Lambda Functions you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "sfn_target_arns" { + description = "The Amazon Resource Name (ARN) of the StepFunctions you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "cloudwatch_target_arns" { + description = "The Amazon Resource Name (ARN) of the Cloudwatch Log Streams you want to use as EventBridge targets" + type = list(string) + default = [] +} + +########################## +# Various custom policies +########################## + +variable "attach_policy_json" { + description = "Controls whether policy_json should be added to IAM role" + type = bool + default = false +} + +variable "attach_policy_jsons" { + description = "Controls whether policy_jsons should be added to IAM role" + type = bool + default = false +} + +variable "attach_policy" { + description = "Controls whether policy should be added to IAM role" + type = bool + default = false +} + +variable "attach_policies" { + description = "Controls whether list of policies should be added to IAM role" + type = bool + default = false +} + +variable "number_of_policy_jsons" { + description = "Number of policies JSON to attach to IAM role" + type = number + default = 0 +} + +variable "number_of_policies" { + description = "Number of policies to attach to IAM role" + type = number + default = 0 +} + +variable "attach_policy_statements" { + description = "Controls whether policy_statements should be added to IAM role" + type = bool + default = false +} + +variable "trusted_entities" { + description = "Step Function additional trusted entities for assuming roles (trust relationship)" + type = list(string) + default = [] +} + +variable "policy_json" { + description = "An additional policy document as JSON to attach to IAM role" + type = string + default = null +} + +variable "policy_jsons" { + description = "List of additional policy documents as JSON to attach to IAM role" + type = list(string) + default = [] +} + +variable "policy" { + description = "An additional policy document ARN to attach to IAM role" + type = string + default = null +} + +variable "policies" { + description = "List of policy statements ARN to attach to IAM role" + type = list(string) + default = [] +} + +variable "policy_statements" { + description = "Map of dynamic policy statements to attach to IAM role" + type = any + default = {} +} diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..2c2f74f --- /dev/null +++ b/versions.tf @@ -0,0 +1,7 @@ +terraform { + required_version = ">= 0.12.26" + + required_providers { + aws = ">= 3.19" + } +}