initial commit
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
<!-- This readme file is generated with terraform-docs -->
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | >= 1.3.0 |
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| aws | >= 5.0 |
|
||||
| random | n/a |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_api_gateway_deployment.apigw-deployment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource |
|
||||
| [aws_api_gateway_integration.api-integration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource |
|
||||
| [aws_api_gateway_integration_response.integration-response](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration_response) | resource |
|
||||
| [aws_api_gateway_method.api-method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource |
|
||||
| [aws_api_gateway_method_response.response_200](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_response) | resource |
|
||||
| [aws_api_gateway_method_settings.apigw-method-settings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_settings) | resource |
|
||||
| [aws_api_gateway_resource.api-res](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource |
|
||||
| [aws_api_gateway_rest_api.api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource |
|
||||
| [aws_api_gateway_rest_api_policy.api-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api_policy) | resource |
|
||||
| [aws_api_gateway_stage.apigw-stage](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage) | resource |
|
||||
| [aws_api_gateway_vpc_link.api-vpc-link](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_vpc_link) | resource |
|
||||
| [aws_cloudwatch_log_group.lambda-logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
|
||||
| [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
|
||||
| [aws_iam_role.lambda-exec-role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
|
||||
| [aws_iam_role_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
|
||||
| [aws_lambda_function.function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |
|
||||
| [aws_lambda_permission.allow_api_gateway](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
|
||||
| [aws_vpc_endpoint.apigw-vpcep](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint) | resource |
|
||||
| [random_id.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
|
||||
| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
|
||||
| [aws_iam_policy_document.api-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
|
||||
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
|
||||
| [aws_vpc.vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) | data source |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| apigw-security-group-id | Security group id of apigateway | `string` | n/a | yes |
|
||||
| apigw-subnet-ids | Subnet IDs of apigateway | `list(string)` | n/a | yes |
|
||||
| apigw-type | Type of apigateway: private or regional | `string` | n/a | yes |
|
||||
| apigw-vpc-id | VPC id of apigateway | `string` | n/a | yes |
|
||||
| apigw-vpc-link-target-arns | Target arns for apigateway VPC link | `list(string)` | `[]` | no |
|
||||
| cloudwatchlog-retention | Cloudwatch log group retention days | `number` | `14` | no |
|
||||
| create-vpc-link | Set true to create vpc link for outbound access to specific targets | `bool` | n/a | yes |
|
||||
| cwl-cmk-key-id | CMK arn for cloudwatch logs encryption | `string` | `null` | no |
|
||||
| description | Description of apigateway | `string` | n/a | yes |
|
||||
| lambda-archive-file | Path to lambda zip archive | `string` | n/a | yes |
|
||||
| lambda-main-function-name | Main python file without the .py extension | `string` | n/a | yes |
|
||||
| lambda-runtime-version | Lambda runtime version | `string` | `"python3.12"` | no |
|
||||
| name | Name of apigateway | `string` | n/a | yes |
|
||||
| resources | Apigateway resources (path\_part) | <pre>map(object({<br> method = string<br> authorization = string<br> integration_type = string<br> content_handling = string<br> }))</pre> | n/a | yes |
|
||||
| stages | apigateway stages | <pre>map(object({<br> description = string<br> variables = map(string)<br> }))</pre> | n/a | yes |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| apigw-id | n/a |
|
||||
| apigw-vpc-endpoints | n/a |
|
||||
|
||||
---
|
||||
## Authorship
|
||||
This module was developed by UPDATE_THIS.
|
||||
@@ -0,0 +1,256 @@
|
||||
resource "aws_api_gateway_rest_api" "api" {
|
||||
name = var.name
|
||||
description = var.description
|
||||
|
||||
dynamic "endpoint_configuration" {
|
||||
for_each = [1]
|
||||
content {
|
||||
types = var.apigw-type == "private" ? ["PRIVATE"] : ["REGIONAL"]
|
||||
vpc_endpoint_ids = var.apigw-type == "private" ? [aws_vpc_endpoint.apigw-vpcep[0].id] : null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# private endpoint for inbound access
|
||||
# to connect to the private api gateway, provide the header x-apigw-api-id
|
||||
# curl -IX GET -H 'x-apigw-api-id:<YOUR_API_ID>' https://<YOUR_VPCE_HOSTNAME>/<STAGE>
|
||||
data "aws_region" "current" {}
|
||||
|
||||
resource "aws_vpc_endpoint" "apigw-vpcep" {
|
||||
count = var.apigw-type == "private" ? 1 : 0
|
||||
private_dns_enabled = false
|
||||
security_group_ids = [var.apigw-security-group-id]
|
||||
service_name = "com.amazonaws.${data.aws_region.current.name}.execute-api"
|
||||
subnet_ids = var.apigw-subnet-ids
|
||||
vpc_endpoint_type = "Interface"
|
||||
vpc_id = var.apigw-vpc-id
|
||||
}
|
||||
|
||||
# vpc link for outbound access
|
||||
resource "aws_api_gateway_vpc_link" "api-vpc-link" {
|
||||
count = var.create-vpc-link ? 1 : 0
|
||||
name = "${var.name}-vpclink"
|
||||
description = "VPC link for apigateway ${var.name}"
|
||||
target_arns = var.apigw-vpc-link-target-arns
|
||||
}
|
||||
|
||||
# Apigw resources, integration, method, responses
|
||||
resource "aws_api_gateway_resource" "api-res" {
|
||||
depends_on = [aws_api_gateway_rest_api_policy.api-policy]
|
||||
for_each = var.resources
|
||||
path_part = each.key
|
||||
parent_id = aws_api_gateway_rest_api.api.root_resource_id
|
||||
rest_api_id = aws_api_gateway_rest_api.api.id
|
||||
}
|
||||
|
||||
resource "aws_api_gateway_method" "api-method" {
|
||||
depends_on = [aws_api_gateway_resource.api-res]
|
||||
for_each = var.resources
|
||||
rest_api_id = aws_api_gateway_rest_api.api.id
|
||||
resource_id = aws_api_gateway_resource.api-res[each.key].id
|
||||
http_method = each.value["method"]
|
||||
authorization = each.value["authorization"]
|
||||
}
|
||||
|
||||
# non-proxy integration
|
||||
resource "aws_api_gateway_integration" "api-integration" {
|
||||
depends_on = [aws_api_gateway_method.api-method]
|
||||
for_each = var.resources
|
||||
rest_api_id = aws_api_gateway_rest_api.api.id
|
||||
resource_id = aws_api_gateway_resource.api-res[each.key].id
|
||||
http_method = aws_api_gateway_method.api-method[each.key].http_method
|
||||
integration_http_method = each.value["method"]
|
||||
type = each.value["integration-type"]
|
||||
content_handling = each.value["content-handling"]
|
||||
uri = aws_lambda_function.function.invoke_arn
|
||||
}
|
||||
|
||||
resource "aws_api_gateway_method_response" "response_200" {
|
||||
depends_on = [aws_api_gateway_method.api-method]
|
||||
for_each = var.resources
|
||||
rest_api_id = aws_api_gateway_rest_api.api.id
|
||||
resource_id = aws_api_gateway_resource.api-res[each.key].id
|
||||
http_method = aws_api_gateway_method.api-method[each.key].http_method
|
||||
status_code = "200"
|
||||
}
|
||||
|
||||
resource "aws_api_gateway_integration_response" "integration-response" {
|
||||
depends_on = [aws_api_gateway_integration.api-integration]
|
||||
for_each = var.resources
|
||||
rest_api_id = aws_api_gateway_rest_api.api.id
|
||||
resource_id = aws_api_gateway_resource.api-res[each.key].id
|
||||
http_method = aws_api_gateway_method.api-method[each.key].http_method
|
||||
status_code = aws_api_gateway_method_response.response_200[each.key].status_code
|
||||
}
|
||||
|
||||
# apigw deployment and stage
|
||||
resource "aws_api_gateway_deployment" "apigw-deployment" {
|
||||
depends_on = [aws_api_gateway_integration.api-integration]
|
||||
rest_api_id = aws_api_gateway_rest_api.api.id
|
||||
|
||||
triggers = {
|
||||
redeployment = sha1(jsonencode(aws_api_gateway_rest_api.api.body))
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_api_gateway_stage" "apigw-stage" {
|
||||
for_each = var.stages
|
||||
depends_on = [aws_api_gateway_rest_api_policy.api-policy, aws_cloudwatch_log_group.this]
|
||||
deployment_id = aws_api_gateway_deployment.apigw-deployment.id
|
||||
rest_api_id = aws_api_gateway_rest_api.api.id
|
||||
stage_name = each.key
|
||||
description = each.value["description"]
|
||||
variables = each.value["variables"]
|
||||
|
||||
access_log_settings {
|
||||
destination_arn = aws_cloudwatch_log_group.this[each.key].arn
|
||||
# https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html
|
||||
format = jsonencode({
|
||||
"requestId" : "$context.requestId",
|
||||
"extendedRequestId" : "$context.extendedRequestId",
|
||||
"ip" : "$context.identity.sourceIp",
|
||||
"caller" : "$context.identity.caller",
|
||||
"user" : "$context.identity.user",
|
||||
"requestTime" : "$context.requestTime",
|
||||
"httpMethod" : "$context.httpMethod",
|
||||
"resourcePath" : "$context.resourcePath",
|
||||
"status" : "$context.status",
|
||||
"protocol" : "$context.protocol",
|
||||
"responseLength" : "$context.responseLength"
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_api_gateway_method_settings" "apigw-method-settings" {
|
||||
depends_on = [aws_api_gateway_rest_api_policy.api-policy]
|
||||
for_each = aws_api_gateway_stage.apigw-stage
|
||||
rest_api_id = aws_api_gateway_rest_api.api.id
|
||||
stage_name = each.value.stage_name
|
||||
method_path = "*/*"
|
||||
|
||||
settings {
|
||||
metrics_enabled = true
|
||||
logging_level = "INFO"
|
||||
}
|
||||
}
|
||||
|
||||
# Cloudwatch log group path: API-Gateway-Execution-Logs_{rest-api-id}/{stage_name}
|
||||
resource "aws_cloudwatch_log_group" "this" {
|
||||
for_each = var.stages
|
||||
name = "API-Gateway-Execution-Logs_${aws_api_gateway_rest_api.api.id}/${each.key}"
|
||||
retention_in_days = var.cloudwatchlog-retention
|
||||
kms_key_id = var.cwl-cmk-key-id
|
||||
}
|
||||
|
||||
# lambda function
|
||||
resource "aws_cloudwatch_log_group" "lambda-logs" {
|
||||
name = "/aws/lambda/${var.name}-lambda-function"
|
||||
retention_in_days = var.cloudwatchlog-retention
|
||||
kms_key_id = var.cwl-cmk-key-id
|
||||
}
|
||||
|
||||
resource "aws_lambda_function" "function" {
|
||||
filename = var.lambda-archive-file
|
||||
function_name = "${var.name}-lambda-function"
|
||||
handler = "main.lambda_handler"
|
||||
role = aws_iam_role.lambda-exec-role.arn
|
||||
runtime = var.lambda-runtime-version
|
||||
# source_code_hash = local.source_code_hash
|
||||
}
|
||||
|
||||
resource "aws_lambda_permission" "allow_api_gateway" {
|
||||
action = "lambda:InvokeFunction"
|
||||
function_name = aws_lambda_function.function.function_name
|
||||
principal = "apigateway.amazonaws.com"
|
||||
}
|
||||
|
||||
# Lambda execution role
|
||||
data "aws_caller_identity" "this" {}
|
||||
|
||||
resource "random_id" "this" {
|
||||
byte_length = 4
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "lambda-exec-role" {
|
||||
name = "lambda-apigw-${var.name}-${random_id.this.dec}"
|
||||
|
||||
assume_role_policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"Service" : "lambda.amazonaws.com"
|
||||
},
|
||||
"Action" : "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "this" {
|
||||
policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "AllowCreationOfCloudwatchLogGroup",
|
||||
"Effect" : "Allow",
|
||||
"Action" : "logs:CreateLogGroup",
|
||||
"Resource" : "arn:aws:logs:ap-east-1:${data.aws_caller_identity.this.account_id}:*"
|
||||
},
|
||||
{
|
||||
"Sid" : "AllowWritingToCloudwatchLogGroup",
|
||||
"Effect" : "Allow",
|
||||
"Action" : [
|
||||
"logs:CreateLogStream",
|
||||
"logs:PutLogEvents"
|
||||
],
|
||||
"Resource" : [
|
||||
"arn:aws:logs:ap-east-1:${data.aws_caller_identity.this.account_id}:log-group:/aws/lambda/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
role = aws_iam_role.lambda-exec-role.id
|
||||
name = "LambdaExecutionPolicy"
|
||||
}
|
||||
|
||||
# apigateway policy
|
||||
data "aws_iam_policy_document" "api-policy" {
|
||||
statement {
|
||||
effect = "Allow"
|
||||
|
||||
principals {
|
||||
type = "AWS"
|
||||
identifiers = ["*"]
|
||||
}
|
||||
|
||||
actions = ["execute-api:Invoke"]
|
||||
resources = [aws_api_gateway_rest_api.api.execution_arn]
|
||||
|
||||
condition {
|
||||
test = "IpAddress"
|
||||
variable = "aws:SourceIp"
|
||||
values = [data.aws_vpc.vpc.cidr_block]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data "aws_vpc" "vpc" {
|
||||
id = var.apigw-vpc-id
|
||||
}
|
||||
resource "aws_api_gateway_rest_api_policy" "api-policy" {
|
||||
rest_api_id = aws_api_gateway_rest_api.api.id
|
||||
policy = data.aws_iam_policy_document.api-policy.json
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
output "apigw-id" {
|
||||
value = aws_api_gateway_rest_api.api.id
|
||||
}
|
||||
|
||||
output "apigw-vpc-endpoints" {
|
||||
value = try(aws_vpc_endpoint.apigw-vpcep.*.dns_entry[0].*.dns_name, null)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
variable "name" {
|
||||
type = string
|
||||
description = "Name of apigateway"
|
||||
}
|
||||
|
||||
variable "description" {
|
||||
type = string
|
||||
description = "Description of apigateway"
|
||||
}
|
||||
|
||||
variable "apigw-type" {
|
||||
type = string
|
||||
description = "Type of apigateway: private or regional"
|
||||
validation {
|
||||
condition = can(regex("^(private|regional)$", var.apigw-type))
|
||||
error_message = "Invalid apigw type, only allowed types are: 'private', 'regional'"
|
||||
}
|
||||
}
|
||||
|
||||
variable "resources" {
|
||||
type = map(object({
|
||||
method = string
|
||||
authorization = string
|
||||
integration_type = string
|
||||
content_handling = string
|
||||
}))
|
||||
description = "Apigateway resources (path_part)"
|
||||
}
|
||||
|
||||
variable "stages" {
|
||||
type = map(object({
|
||||
description = string
|
||||
variables = map(string)
|
||||
}))
|
||||
description = "apigateway stages"
|
||||
}
|
||||
|
||||
variable "lambda-archive-file" {
|
||||
type = string
|
||||
description = "Path to lambda zip archive"
|
||||
}
|
||||
|
||||
variable "lambda-runtime-version" {
|
||||
type = string
|
||||
description = "Lambda runtime version"
|
||||
default = "python3.12"
|
||||
}
|
||||
|
||||
variable "lambda-main-function-name" {
|
||||
type = string
|
||||
description = "Main python file without the .py extension"
|
||||
}
|
||||
|
||||
variable "apigw-vpc-id" {
|
||||
type = string
|
||||
description = "VPC id of apigateway"
|
||||
}
|
||||
|
||||
variable "apigw-subnet-ids" {
|
||||
type = list(string)
|
||||
description = "Subnet IDs of apigateway"
|
||||
}
|
||||
|
||||
variable "apigw-security-group-id" {
|
||||
type = string
|
||||
description = "Security group id of apigateway"
|
||||
}
|
||||
|
||||
variable "create-vpc-link" {
|
||||
type = bool
|
||||
description = "Set true to create vpc link for outbound access to specific targets"
|
||||
}
|
||||
|
||||
variable "apigw-vpc-link-target-arns" {
|
||||
type = list(string)
|
||||
description = "Target arns for apigateway VPC link"
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "cloudwatchlog-retention" {
|
||||
type = number
|
||||
description = "Cloudwatch log group retention days"
|
||||
default = 14
|
||||
}
|
||||
|
||||
variable "cwl-cmk-key-id" {
|
||||
type = string
|
||||
description = "CMK arn for cloudwatch logs encryption"
|
||||
default = null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = ">= 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
# 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
|
||||
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
|
||||
[*.{tf,tfvars}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[*.md]
|
||||
max_line_length = 0
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[Makefile]
|
||||
tab_width = 2
|
||||
indent_style = tab
|
||||
|
||||
[COMMIT_EDITMSG]
|
||||
max_line_length = 0
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
name: 'Lock Threads'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '50 1 * * *'
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v4
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-comment: >
|
||||
I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.
|
||||
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
|
||||
issue-inactive-days: '30'
|
||||
pr-comment: >
|
||||
I'm going to lock this pull request because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.
|
||||
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
|
||||
pr-inactive-days: '30'
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
name: 'Validate PR title'
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
main:
|
||||
name: Validate PR title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Please look up the latest version from
|
||||
# https://github.com/amannn/action-semantic-pull-request/releases
|
||||
- uses: amannn/action-semantic-pull-request@v5.0.2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
# Configure which types are allowed.
|
||||
# Default: https://github.com/commitizen/conventional-commit-types
|
||||
types: |
|
||||
fix
|
||||
feat
|
||||
docs
|
||||
ci
|
||||
chore
|
||||
# Configure that a scope must always be provided.
|
||||
requireScope: false
|
||||
# Configure additional validation for the subject based on a regex.
|
||||
# This example ensures the subject starts with an uppercase character.
|
||||
subjectPattern: ^[A-Z].+$
|
||||
# If `subjectPattern` is configured, you can use this property to override
|
||||
# the default error message that is shown when the pattern doesn't match.
|
||||
# The variables `subject` and `title` can be used within the message.
|
||||
subjectPatternError: |
|
||||
The subject "{subject}" found in the pull request title "{title}"
|
||||
didn't match the configured pattern. Please ensure that the subject
|
||||
starts with an uppercase character.
|
||||
# For work-in-progress PRs you can typically use draft pull requests
|
||||
# from Github. However, private repositories on the free plan don't have
|
||||
# this option and therefore this action allows you to opt-in to using the
|
||||
# special "[WIP]" prefix to indicate this state. This will avoid the
|
||||
# validation of the PR title and the pull request checks remain pending.
|
||||
# Note that a second check will be reported if this is enabled.
|
||||
wip: true
|
||||
# When using "Squash and merge" on a PR with only one commit, GitHub
|
||||
# will suggest using that commit message instead of the PR title for the
|
||||
# merge commit, and it's easy to commit this by mistake. Enable this option
|
||||
# to also validate the commit message for one commit PRs.
|
||||
validateSingleCommit: false
|
||||
Vendored
+83
@@ -0,0 +1,83 @@
|
||||
name: Pre-Commit
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
|
||||
env:
|
||||
TERRAFORM_DOCS_VERSION: v0.16.0
|
||||
TFLINT_VERSION: v0.44.1
|
||||
|
||||
jobs:
|
||||
collectInputs:
|
||||
name: Collect workflow inputs
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
directories: ${{ steps.dirs.outputs.directories }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Get root directories
|
||||
id: dirs
|
||||
uses: clowdhaus/terraform-composite-actions/directories@v1.8.3
|
||||
|
||||
preCommitMinVersions:
|
||||
name: Min TF pre-commit
|
||||
needs: collectInputs
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
directory: ${{ fromJson(needs.collectInputs.outputs.directories) }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Terraform min/max versions
|
||||
id: minMax
|
||||
uses: clowdhaus/terraform-min-max@v1.2.4
|
||||
with:
|
||||
directory: ${{ matrix.directory }}
|
||||
|
||||
- name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }}
|
||||
# Run only validate pre-commit check on min version supported
|
||||
if: ${{ matrix.directory != '.' }}
|
||||
uses: clowdhaus/terraform-composite-actions/pre-commit@v1.8.3
|
||||
with:
|
||||
terraform-version: ${{ steps.minMax.outputs.minVersion }}
|
||||
tflint-version: ${{ env.TFLINT_VERSION }}
|
||||
args: 'terraform_validate --color=always --show-diff-on-failure --files ${{ matrix.directory }}/*'
|
||||
|
||||
- name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }}
|
||||
# Run only validate pre-commit check on min version supported
|
||||
if: ${{ matrix.directory == '.' }}
|
||||
uses: clowdhaus/terraform-composite-actions/pre-commit@v1.8.3
|
||||
with:
|
||||
terraform-version: ${{ steps.minMax.outputs.minVersion }}
|
||||
tflint-version: ${{ env.TFLINT_VERSION }}
|
||||
args: 'terraform_validate --color=always --show-diff-on-failure --files $(ls *.tf)'
|
||||
|
||||
preCommitMaxVersion:
|
||||
name: Max TF pre-commit
|
||||
runs-on: ubuntu-latest
|
||||
needs: collectInputs
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Terraform min/max versions
|
||||
id: minMax
|
||||
uses: clowdhaus/terraform-min-max@v1.2.4
|
||||
|
||||
- name: Pre-commit Terraform ${{ steps.minMax.outputs.maxVersion }}
|
||||
uses: clowdhaus/terraform-composite-actions/pre-commit@v1.8.3
|
||||
with:
|
||||
terraform-version: ${{ steps.minMax.outputs.maxVersion }}
|
||||
tflint-version: ${{ env.TFLINT_VERSION }}
|
||||
terraform-docs-version: ${{ env.TERRAFORM_DOCS_VERSION }}
|
||||
install-hcledit: true
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
paths:
|
||||
- '**/*.tpl'
|
||||
- '**/*.py'
|
||||
- '**/*.tf'
|
||||
- '.github/workflows/release.yml'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
# Skip running release workflow on forks
|
||||
if: github.repository_owner == 'terraform-aws-modules'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Release
|
||||
uses: cycjimmy/semantic-release-action@v3
|
||||
with:
|
||||
semantic_version: 18.0.0
|
||||
extra_plugins: |
|
||||
@semantic-release/changelog@6.0.0
|
||||
@semantic-release/git@10.0.0
|
||||
conventional-changelog-conventionalcommits@4.6.3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_TOKEN }}
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
name: 'Mark or close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v6
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Staling issues and PR's
|
||||
days-before-stale: 30
|
||||
stale-issue-label: stale
|
||||
stale-pr-label: stale
|
||||
stale-issue-message: |
|
||||
This issue has been automatically marked as stale because it has been open 30 days
|
||||
with no activity. Remove stale label or comment or this issue will be closed in 10 days
|
||||
stale-pr-message: |
|
||||
This PR has been automatically marked as stale because it has been open 30 days
|
||||
with no activity. Remove stale label or comment or this PR will be closed in 10 days
|
||||
# Not stale if have this labels or part of milestone
|
||||
exempt-issue-labels: bug,wip,on-hold
|
||||
exempt-pr-labels: bug,wip,on-hold
|
||||
exempt-all-milestones: true
|
||||
# Close issue operations
|
||||
# Label will be automatically removed if the issues are no longer closed nor locked.
|
||||
days-before-close: 10
|
||||
delete-branch: true
|
||||
close-issue-message: This issue was automatically closed because of stale in 10 days
|
||||
close-pr-message: This PR was automatically closed because of stale in 10 days
|
||||
@@ -0,0 +1,32 @@
|
||||
# Local .terraform directories
|
||||
**/.terraform/*
|
||||
|
||||
# Terraform lockfile
|
||||
.terraform.lock.hcl
|
||||
|
||||
# .tfstate files
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
|
||||
# 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
|
||||
|
||||
# Zip archive
|
||||
*.zip
|
||||
@@ -0,0 +1,30 @@
|
||||
repos:
|
||||
- repo: https://github.com/antonbabenko/pre-commit-terraform
|
||||
rev: v1.86.0
|
||||
hooks:
|
||||
- id: terraform_fmt
|
||||
- id: terraform_wrapper_module_for_each
|
||||
- id: terraform_validate
|
||||
- id: terraform_docs
|
||||
args:
|
||||
- "--args=--lockfile=false"
|
||||
- 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: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.5.0
|
||||
hooks:
|
||||
- id: check-merge-conflict
|
||||
- id: end-of-file-fixer
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"branches": [
|
||||
"main",
|
||||
"master"
|
||||
],
|
||||
"ci": false,
|
||||
"plugins": [
|
||||
[
|
||||
"@semantic-release/commit-analyzer",
|
||||
{
|
||||
"preset": "conventionalcommits"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/release-notes-generator",
|
||||
{
|
||||
"preset": "conventionalcommits"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/github",
|
||||
{
|
||||
"successComment": "This ${issue.pull_request ? 'PR is included' : 'issue has been resolved'} in version ${nextRelease.version} :tada:",
|
||||
"labels": false,
|
||||
"releasedLabels": false
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/changelog",
|
||||
{
|
||||
"changelogFile": "CHANGELOG.md",
|
||||
"changelogTitle": "# Changelog\n\nAll notable changes to this project will be documented in this file."
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/git",
|
||||
{
|
||||
"assets": [
|
||||
"CHANGELOG.md"
|
||||
],
|
||||
"message": "chore(release): version ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [3.1.0](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v3.0.0...v3.1.0) (2024-02-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add variable create_route to control creation of route ([#98](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/98)) ([68ad2b1](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/68ad2b183a4872e29890784290b5925beee1dd29))
|
||||
|
||||
## [3.0.0](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v2.2.2...v3.0.0) (2024-02-12)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* Added the fail_on_warnings variable, bumped Terraform version to 1.0+ (#96)
|
||||
|
||||
### Features
|
||||
|
||||
* Added the fail_on_warnings variable, bumped Terraform version to 1.0+ ([#96](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/96)) ([26859db](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/26859db0a5d651903469f6fabeda1e341867c45d))
|
||||
|
||||
### [2.2.2](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v2.2.1...v2.2.2) (2023-01-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use a version for to avoid GitHub API rate limiting on CI workflows ([#85](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/85)) ([9229fa2](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/9229fa2ec7f01f9187b0ddcae3a29929e8146417))
|
||||
|
||||
### [2.2.1](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v2.2.0...v2.2.1) (2022-10-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update CI configuration files to use latest version ([#84](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/84)) ([13bd65e](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/13bd65e192cb39f25a7e7bd281470dd1f7c073bd))
|
||||
|
||||
## [2.2.0](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v2.1.0...v2.2.0) (2022-09-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Enable route_settings in default stage ([#80](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/80)) ([a13ef33](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/a13ef3308fc0b4efef53f7fefb8bc7f8012a8336))
|
||||
|
||||
## [2.1.0](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v2.0.0...v2.1.0) (2022-08-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Added API GW Authorizer IDs to outputs ([#76](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/76)) ([05da6b1](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/05da6b19a0150d2d39db97968fa7214e9e4fa580))
|
||||
|
||||
## [2.0.0](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.9.0...v2.0.0) (2022-06-15)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* Upgraded AWS provider to v4 everywhere (#74)
|
||||
|
||||
### Features
|
||||
|
||||
* Upgraded AWS provider to v4 everywhere ([#74](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/74)) ([2f8ad61](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/2f8ad61a8668eb7559115f31e62c502ed2ea09c3))
|
||||
|
||||
## [1.9.0](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.8.0...v1.9.0) (2022-06-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add pass-through of ownership_verification_certificate_arn to domain_name ([#72](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/72)) ([5709873](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/57098730dc48785f0836f9eb322008b054f91134))
|
||||
|
||||
## [1.8.0](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.7.0...v1.8.0) (2022-05-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Added enable_simple_responses and authorizer_credentials_arn to authorizers ([#71](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/71)) ([1467b95](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/1467b95c8309d82332857a9c2790ca25f2edc2ec))
|
||||
|
||||
## [1.7.0](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.6.1...v1.7.0) (2022-04-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Added support for ttl in authorizer resource ([#68](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/68)) ([ce1faf9](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/ce1faf96b191228bf891864f50d284078f54b0a0))
|
||||
|
||||
### [1.6.1](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.6.0...v1.6.1) (2022-04-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add support for passing authorization_scopes on routes with JWT authorizer ([#67](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/67)) ([c2b8d6b](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/c2b8d6bd8b11fa83ccd13f3ccc74844d328f59ad))
|
||||
|
||||
## [1.6.0](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.5.1...v1.6.0) (2022-03-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Added support for Authorizers ([#64](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/64)) ([5cd32e0](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/5cd32e0360c866c25d8a8c6300e638143335a665))
|
||||
|
||||
## [1.5.1](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.5.0...v1.5.1) (2021-11-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update CI/CD process to enable auto-release workflow ([#60](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/60)) ([55f5c1d](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/commit/55f5c1d74b4b61cf228f66c2d4a7f940e90f01b7))
|
||||
|
||||
<a name="v1.5.0"></a>
|
||||
## [v1.5.0] - 2021-11-01
|
||||
|
||||
- feat: Add support for response_parameters in integrations ([#58](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/58))
|
||||
|
||||
|
||||
<a name="v1.4.0"></a>
|
||||
## [v1.4.0] - 2021-09-23
|
||||
|
||||
- Feat: Add create_before_destroy lifecycle to integration resources ([#55](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/55))
|
||||
|
||||
|
||||
<a name="v1.3.0"></a>
|
||||
## [v1.3.0] - 2021-09-16
|
||||
|
||||
- fix: Fixed output when create_api_domain_name is false ([#44](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/44))
|
||||
- chore: Fixed GH Action with terraform-docs
|
||||
|
||||
|
||||
<a name="v1.2.0"></a>
|
||||
## [v1.2.0] - 2021-08-26
|
||||
|
||||
- feat: Add support for tls_config in integrations ([#51](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/51))
|
||||
- fix: Fixed source_arn in example (fixes [#41](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/41))
|
||||
|
||||
|
||||
<a name="v1.1.0"></a>
|
||||
## [v1.1.0] - 2021-05-25
|
||||
|
||||
- chore: Remove check boxes that don't render properly in module doc ([#40](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/40))
|
||||
- chore: update CI/CD to use stable `terraform-docs` release artifact and discoverable Apache2.0 license ([#38](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/38))
|
||||
- chore: Updated versions in README ([#37](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/37))
|
||||
|
||||
|
||||
<a name="v1.0.0"></a>
|
||||
## [v1.0.0] - 2021-04-26
|
||||
|
||||
- feat: Shorten outputs (removing this_), added domain name to outputs ([#34](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/34))
|
||||
|
||||
|
||||
<a name="v0.16.0"></a>
|
||||
## [v0.16.0] - 2021-04-25
|
||||
|
||||
- feat: Add support for default_route_settings ([#32](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/32))
|
||||
|
||||
|
||||
<a name="v0.15.0"></a>
|
||||
## [v0.15.0] - 2021-04-24
|
||||
|
||||
- feat: Added support for mTLS and the ability to disable default endpoint ([#29](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/29))
|
||||
- chore: update documentation and pin `terraform_docs` version to avoid future changes ([#28](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/28))
|
||||
|
||||
|
||||
<a name="v0.14.0"></a>
|
||||
## [v0.14.0] - 2021-03-16
|
||||
|
||||
- feat: Add support for OpenAPI definition ([#27](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/27))
|
||||
|
||||
|
||||
<a name="v0.13.0"></a>
|
||||
## [v0.13.0] - 2021-03-10
|
||||
|
||||
- feat: Added example of step-functions integration ([#26](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/26))
|
||||
|
||||
|
||||
<a name="v0.12.0"></a>
|
||||
## [v0.12.0] - 2021-03-09
|
||||
|
||||
- feat: Added VPC integration ([#25](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/25))
|
||||
|
||||
|
||||
<a name="v0.11.0"></a>
|
||||
## [v0.11.0] - 2021-03-06
|
||||
|
||||
- fix: Remove workaround related to passthrough_behavior for older providers ([#24](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/24))
|
||||
- chore: align ci-cd static checks to use individual minimum Terraform versions ([#23](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/23))
|
||||
- fix: bump min supported version due to types unsupported on current ([#22](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/22))
|
||||
- chore: add ci-cd workflow for pre-commit checks ([#21](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/21))
|
||||
|
||||
|
||||
<a name="v0.10.0"></a>
|
||||
## [v0.10.0] - 2021-02-20
|
||||
|
||||
- chore: update documentation based on latest `terraform-docs` which includes module and resource sections ([#19](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/19))
|
||||
|
||||
|
||||
<a name="v0.9.0"></a>
|
||||
## [v0.9.0] - 2021-02-14
|
||||
|
||||
- feat: support authorization_type and authorizer_id on routes ([#17](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/17))
|
||||
|
||||
|
||||
<a name="v0.8.0"></a>
|
||||
## [v0.8.0] - 2021-01-14
|
||||
|
||||
- feat: New useful outputs to use with route53 ([#11](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/11))
|
||||
|
||||
|
||||
<a name="v0.7.0"></a>
|
||||
## [v0.7.0] - 2021-01-14
|
||||
|
||||
- chore: Updated example after lambda module has been updated ([#16](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/16))
|
||||
- fix: default API Gateway integration method is POST ([#14](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/14))
|
||||
|
||||
|
||||
<a name="v0.6.0"></a>
|
||||
## [v0.6.0] - 2021-01-14
|
||||
|
||||
- fix: Integration URI is not always a lambda_arn ([#15](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/15))
|
||||
|
||||
|
||||
<a name="v0.5.0"></a>
|
||||
## [v0.5.0] - 2020-11-24
|
||||
|
||||
- fix: Updated supported Terraform versions
|
||||
|
||||
|
||||
<a name="v0.4.0"></a>
|
||||
## [v0.4.0] - 2020-09-08
|
||||
|
||||
- feat: add VPC Links resource to allow access to private resources ([#3](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/3))
|
||||
|
||||
|
||||
<a name="v0.3.0"></a>
|
||||
## [v0.3.0] - 2020-08-14
|
||||
|
||||
- feat: Updated version requirements for AWS provider v3 and Terraform 0.13
|
||||
- Added route53 record into example (closes [#1](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/issues/1))
|
||||
- Improved complete example
|
||||
|
||||
|
||||
<a name="v0.2.0"></a>
|
||||
## [v0.2.0] - 2020-06-07
|
||||
|
||||
- Added support for access logs
|
||||
|
||||
|
||||
<a name="v0.1.0"></a>
|
||||
## v0.1.0 - 2020-06-05
|
||||
|
||||
- Adding API Gateway module
|
||||
|
||||
|
||||
[Unreleased]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.5.0...HEAD
|
||||
[v1.5.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.4.0...v1.5.0
|
||||
[v1.4.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.3.0...v1.4.0
|
||||
[v1.3.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.2.0...v1.3.0
|
||||
[v1.2.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.1.0...v1.2.0
|
||||
[v1.1.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v1.0.0...v1.1.0
|
||||
[v1.0.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.16.0...v1.0.0
|
||||
[v0.16.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.15.0...v0.16.0
|
||||
[v0.15.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.14.0...v0.15.0
|
||||
[v0.14.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.13.0...v0.14.0
|
||||
[v0.13.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.12.0...v0.13.0
|
||||
[v0.12.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.11.0...v0.12.0
|
||||
[v0.11.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.10.0...v0.11.0
|
||||
[v0.10.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.9.0...v0.10.0
|
||||
[v0.9.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.8.0...v0.9.0
|
||||
[v0.8.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.7.0...v0.8.0
|
||||
[v0.7.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.6.0...v0.7.0
|
||||
[v0.6.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.5.0...v0.6.0
|
||||
[v0.5.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.4.0...v0.5.0
|
||||
[v0.4.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.3.0...v0.4.0
|
||||
[v0.3.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.2.0...v0.3.0
|
||||
[v0.2.0]: https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/compare/v0.1.0...v0.2.0
|
||||
@@ -0,0 +1,176 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -0,0 +1,216 @@
|
||||
# AWS API Gateway v2 (HTTP/Websocket) Terraform module
|
||||
|
||||
Terraform module which creates API Gateway version 2 with HTTP/Websocket capabilities.
|
||||
|
||||
This Terraform module is part of [serverless.tf framework](https://serverless.tf), which aims to simplify all operations when working with the serverless in Terraform.
|
||||
|
||||
## Supported Features
|
||||
|
||||
- Support many of features of HTTP API Gateway, but rather limited support for WebSocket API Gateway
|
||||
- Conditional creation for many types of resources
|
||||
|
||||
## Feature Roadmap
|
||||
|
||||
- Some features are still missing (especially for WebSocket support)
|
||||
|
||||
## Usage
|
||||
|
||||
### HTTP API Gateway
|
||||
|
||||
```hcl
|
||||
module "api_gateway" {
|
||||
source = "terraform-aws-modules/apigateway-v2/aws"
|
||||
|
||||
name = "dev-http"
|
||||
description = "My awesome HTTP API Gateway"
|
||||
protocol_type = "HTTP"
|
||||
|
||||
cors_configuration = {
|
||||
allow_headers = ["content-type", "x-amz-date", "authorization", "x-api-key", "x-amz-security-token", "x-amz-user-agent"]
|
||||
allow_methods = ["*"]
|
||||
allow_origins = ["*"]
|
||||
}
|
||||
|
||||
# Custom domain
|
||||
domain_name = "terraform-aws-modules.modules.tf"
|
||||
domain_name_certificate_arn = "arn:aws:acm:eu-west-1:052235179155:certificate/2b3a7ed9-05e1-4f9e-952b-27744ba06da6"
|
||||
|
||||
# Access logs
|
||||
default_stage_access_log_destination_arn = "arn:aws:logs:eu-west-1:835367859851:log-group:debug-apigateway"
|
||||
default_stage_access_log_format = "$context.identity.sourceIp - - [$context.requestTime] \"$context.httpMethod $context.routeKey $context.protocol\" $context.status $context.responseLength $context.requestId $context.integrationErrorMessage"
|
||||
|
||||
# Routes and integrations
|
||||
integrations = {
|
||||
"POST /" = {
|
||||
lambda_arn = "arn:aws:lambda:eu-west-1:052235179155:function:my-function"
|
||||
payload_format_version = "2.0"
|
||||
timeout_milliseconds = 12000
|
||||
}
|
||||
|
||||
"GET /some-route-with-authorizer" = {
|
||||
integration_type = "HTTP_PROXY"
|
||||
integration_uri = "some url"
|
||||
authorizer_key = "azure"
|
||||
}
|
||||
|
||||
"$default" = {
|
||||
lambda_arn = "arn:aws:lambda:eu-west-1:052235179155:function:my-default-function"
|
||||
}
|
||||
}
|
||||
|
||||
authorizers = {
|
||||
"azure" = {
|
||||
authorizer_type = "JWT"
|
||||
identity_sources = "$request.header.Authorization"
|
||||
name = "azure-auth"
|
||||
audience = ["d6a38afd-45d6-4874-d1aa-3c5c558aqcc2"]
|
||||
issuer = "https://sts.windows.net/aaee026e-8f37-410e-8869-72d9154873e4/"
|
||||
}
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "http-apigateway"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 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 "api_gateway" {
|
||||
source = "terraform-aws-modules/apigateway-v2/aws"
|
||||
|
||||
create = false # to disable all resources
|
||||
|
||||
create_api_gateway = false # to control creation of API Gateway
|
||||
create_api_domain_name = false # to control creation of API Gateway Domain Name
|
||||
create_default_stage = false # to control creation of "$default" stage
|
||||
create_default_stage_api_mapping = false # to control creation of "$default" stage and API mapping
|
||||
create_routes_and_integrations = false # to control creation of routes and integrations
|
||||
create_vpc_link = false # to control creation of VPC link
|
||||
|
||||
integrations= {
|
||||
"GET /" = {
|
||||
create_route = false # to control creation of route
|
||||
}
|
||||
}
|
||||
|
||||
# ... omitted
|
||||
}
|
||||
```
|
||||
|
||||
## Notes:
|
||||
|
||||
- Make sure provider block has the setting of `skip_requesting_account_id` disabled (`false`) to produce correct value in the `execution_arn`.
|
||||
|
||||
## Examples
|
||||
|
||||
- [Complete HTTP](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/tree/master/examples/complete-http) - Create API Gateway, authorizer, domain name, stage and other resources in various combinations
|
||||
- [HTTP with VPC Link](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/tree/master/examples/vpc-link-http) - Create API Gateway with VPC link and integration with resources in VPC (eg. ALB)
|
||||
|
||||
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
|
||||
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.0 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.0 |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_apigatewayv2_api.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_api) | resource |
|
||||
| [aws_apigatewayv2_api_mapping.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_api_mapping) | resource |
|
||||
| [aws_apigatewayv2_authorizer.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_authorizer) | resource |
|
||||
| [aws_apigatewayv2_domain_name.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_domain_name) | resource |
|
||||
| [aws_apigatewayv2_integration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_integration) | resource |
|
||||
| [aws_apigatewayv2_route.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_route) | resource |
|
||||
| [aws_apigatewayv2_stage.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_stage) | resource |
|
||||
| [aws_apigatewayv2_vpc_link.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_vpc_link) | resource |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| <a name="input_api_key_selection_expression"></a> [api\_key\_selection\_expression](#input\_api\_key\_selection\_expression) | An API key selection expression. Valid values: $context.authorizer.usageIdentifierKey, $request.header.x-api-key. | `string` | `"$request.header.x-api-key"` | no |
|
||||
| <a name="input_api_version"></a> [api\_version](#input\_api\_version) | A version identifier for the API | `string` | `null` | no |
|
||||
| <a name="input_authorizers"></a> [authorizers](#input\_authorizers) | Map of API gateway authorizers | `map(any)` | `{}` | no |
|
||||
| <a name="input_body"></a> [body](#input\_body) | An OpenAPI specification that defines the set of routes and integrations to create as part of the HTTP APIs. Supported only for HTTP APIs. | `string` | `null` | no |
|
||||
| <a name="input_cors_configuration"></a> [cors\_configuration](#input\_cors\_configuration) | The cross-origin resource sharing (CORS) configuration. Applicable for HTTP APIs. | `any` | `{}` | no |
|
||||
| <a name="input_create"></a> [create](#input\_create) | Controls if API Gateway resources should be created | `bool` | `true` | no |
|
||||
| <a name="input_create_api_domain_name"></a> [create\_api\_domain\_name](#input\_create\_api\_domain\_name) | Whether to create API domain name resource | `bool` | `true` | no |
|
||||
| <a name="input_create_api_gateway"></a> [create\_api\_gateway](#input\_create\_api\_gateway) | Whether to create API Gateway | `bool` | `true` | no |
|
||||
| <a name="input_create_default_stage"></a> [create\_default\_stage](#input\_create\_default\_stage) | Whether to create default stage | `bool` | `true` | no |
|
||||
| <a name="input_create_default_stage_api_mapping"></a> [create\_default\_stage\_api\_mapping](#input\_create\_default\_stage\_api\_mapping) | Whether to create default stage API mapping | `bool` | `true` | no |
|
||||
| <a name="input_create_routes_and_integrations"></a> [create\_routes\_and\_integrations](#input\_create\_routes\_and\_integrations) | Whether to create routes and integrations resources | `bool` | `true` | no |
|
||||
| <a name="input_create_vpc_link"></a> [create\_vpc\_link](#input\_create\_vpc\_link) | Whether to create VPC links | `bool` | `true` | no |
|
||||
| <a name="input_credentials_arn"></a> [credentials\_arn](#input\_credentials\_arn) | Part of quick create. Specifies any credentials required for the integration. Applicable for HTTP APIs. | `string` | `null` | no |
|
||||
| <a name="input_default_route_settings"></a> [default\_route\_settings](#input\_default\_route\_settings) | Settings for default route | `map(string)` | `{}` | no |
|
||||
| <a name="input_default_stage_access_log_destination_arn"></a> [default\_stage\_access\_log\_destination\_arn](#input\_default\_stage\_access\_log\_destination\_arn) | Default stage's ARN of the CloudWatch Logs log group to receive access logs. Any trailing :* is trimmed from the ARN. | `string` | `null` | no |
|
||||
| <a name="input_default_stage_access_log_format"></a> [default\_stage\_access\_log\_format](#input\_default\_stage\_access\_log\_format) | Default stage's single line format of the access logs of data, as specified by selected $context variables. | `string` | `null` | no |
|
||||
| <a name="input_default_stage_tags"></a> [default\_stage\_tags](#input\_default\_stage\_tags) | A mapping of tags to assign to the default stage resource. | `map(string)` | `{}` | no |
|
||||
| <a name="input_description"></a> [description](#input\_description) | The description of the API. | `string` | `null` | no |
|
||||
| <a name="input_disable_execute_api_endpoint"></a> [disable\_execute\_api\_endpoint](#input\_disable\_execute\_api\_endpoint) | Whether clients can invoke the API by using the default execute-api endpoint. To require that clients use a custom domain name to invoke the API, disable the default endpoint | `string` | `false` | no |
|
||||
| <a name="input_domain_name"></a> [domain\_name](#input\_domain\_name) | The domain name to use for API gateway | `string` | `null` | no |
|
||||
| <a name="input_domain_name_certificate_arn"></a> [domain\_name\_certificate\_arn](#input\_domain\_name\_certificate\_arn) | The ARN of an AWS-managed certificate that will be used by the endpoint for the domain name | `string` | `null` | no |
|
||||
| <a name="input_domain_name_ownership_verification_certificate_arn"></a> [domain\_name\_ownership\_verification\_certificate\_arn](#input\_domain\_name\_ownership\_verification\_certificate\_arn) | ARN of the AWS-issued certificate used to validate custom domain ownership (when certificate\_arn is issued via an ACM Private CA or mutual\_tls\_authentication is configured with an ACM-imported certificate.) | `string` | `null` | no |
|
||||
| <a name="input_domain_name_tags"></a> [domain\_name\_tags](#input\_domain\_name\_tags) | A mapping of tags to assign to API domain name resource. | `map(string)` | `{}` | no |
|
||||
| <a name="input_fail_on_warnings"></a> [fail\_on\_warnings](#input\_fail\_on\_warnings) | Whether warnings should return an error while API Gateway is creating or updating the resource using an OpenAPI specification. Defaults to false. Applicable for HTTP APIs. | `bool` | `false` | no |
|
||||
| <a name="input_integrations"></a> [integrations](#input\_integrations) | Map of API gateway routes with integrations | `map(any)` | `{}` | no |
|
||||
| <a name="input_mutual_tls_authentication"></a> [mutual\_tls\_authentication](#input\_mutual\_tls\_authentication) | An Amazon S3 URL that specifies the truststore for mutual TLS authentication as well as version, keyed at uri and version | `map(string)` | `{}` | no |
|
||||
| <a name="input_name"></a> [name](#input\_name) | The name of the API | `string` | `""` | no |
|
||||
| <a name="input_protocol_type"></a> [protocol\_type](#input\_protocol\_type) | The API protocol. Valid values: HTTP, WEBSOCKET | `string` | `"HTTP"` | no |
|
||||
| <a name="input_route_key"></a> [route\_key](#input\_route\_key) | Part of quick create. Specifies any route key. Applicable for HTTP APIs. | `string` | `null` | no |
|
||||
| <a name="input_route_selection_expression"></a> [route\_selection\_expression](#input\_route\_selection\_expression) | The route selection expression for the API. | `string` | `"$request.method $request.path"` | no |
|
||||
| <a name="input_tags"></a> [tags](#input\_tags) | A mapping of tags to assign to API gateway resources. | `map(string)` | `{}` | no |
|
||||
| <a name="input_target"></a> [target](#input\_target) | Part of quick create. Quick create produces an API with an integration, a default catch-all route, and a default stage which is configured to automatically deploy changes. For HTTP integrations, specify a fully qualified URL. For Lambda integrations, specify a function ARN. The type of the integration will be HTTP\_PROXY or AWS\_PROXY, respectively. Applicable for HTTP APIs. | `string` | `null` | no |
|
||||
| <a name="input_vpc_link_tags"></a> [vpc\_link\_tags](#input\_vpc\_link\_tags) | A map of tags to add to the VPC Link | `map(string)` | `{}` | no |
|
||||
| <a name="input_vpc_links"></a> [vpc\_links](#input\_vpc\_links) | Map of VPC Links details to create | `map(any)` | `{}` | no |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| <a name="output_apigatewayv2_api_api_endpoint"></a> [apigatewayv2\_api\_api\_endpoint](#output\_apigatewayv2\_api\_api\_endpoint) | The URI of the API |
|
||||
| <a name="output_apigatewayv2_api_arn"></a> [apigatewayv2\_api\_arn](#output\_apigatewayv2\_api\_arn) | The ARN of the API |
|
||||
| <a name="output_apigatewayv2_api_execution_arn"></a> [apigatewayv2\_api\_execution\_arn](#output\_apigatewayv2\_api\_execution\_arn) | The ARN prefix to be used in an aws\_lambda\_permission's source\_arn attribute or in an aws\_iam\_policy to authorize access to the @connections API. |
|
||||
| <a name="output_apigatewayv2_api_id"></a> [apigatewayv2\_api\_id](#output\_apigatewayv2\_api\_id) | The API identifier |
|
||||
| <a name="output_apigatewayv2_api_mapping_id"></a> [apigatewayv2\_api\_mapping\_id](#output\_apigatewayv2\_api\_mapping\_id) | The API mapping identifier. |
|
||||
| <a name="output_apigatewayv2_authorizer_id"></a> [apigatewayv2\_authorizer\_id](#output\_apigatewayv2\_authorizer\_id) | The map of API Gateway Authorizer identifiers |
|
||||
| <a name="output_apigatewayv2_domain_name_api_mapping_selection_expression"></a> [apigatewayv2\_domain\_name\_api\_mapping\_selection\_expression](#output\_apigatewayv2\_domain\_name\_api\_mapping\_selection\_expression) | The API mapping selection expression for the domain name |
|
||||
| <a name="output_apigatewayv2_domain_name_arn"></a> [apigatewayv2\_domain\_name\_arn](#output\_apigatewayv2\_domain\_name\_arn) | The ARN of the domain name |
|
||||
| <a name="output_apigatewayv2_domain_name_configuration"></a> [apigatewayv2\_domain\_name\_configuration](#output\_apigatewayv2\_domain\_name\_configuration) | The domain name configuration |
|
||||
| <a name="output_apigatewayv2_domain_name_hosted_zone_id"></a> [apigatewayv2\_domain\_name\_hosted\_zone\_id](#output\_apigatewayv2\_domain\_name\_hosted\_zone\_id) | The Amazon Route 53 Hosted Zone ID of the endpoint |
|
||||
| <a name="output_apigatewayv2_domain_name_id"></a> [apigatewayv2\_domain\_name\_id](#output\_apigatewayv2\_domain\_name\_id) | The domain name identifier |
|
||||
| <a name="output_apigatewayv2_domain_name_target_domain_name"></a> [apigatewayv2\_domain\_name\_target\_domain\_name](#output\_apigatewayv2\_domain\_name\_target\_domain\_name) | The target domain name |
|
||||
| <a name="output_apigatewayv2_vpc_link_arn"></a> [apigatewayv2\_vpc\_link\_arn](#output\_apigatewayv2\_vpc\_link\_arn) | The map of VPC Link ARNs |
|
||||
| <a name="output_apigatewayv2_vpc_link_id"></a> [apigatewayv2\_vpc\_link\_id](#output\_apigatewayv2\_vpc\_link\_id) | The map of VPC Link identifiers |
|
||||
| <a name="output_default_apigatewayv2_stage_arn"></a> [default\_apigatewayv2\_stage\_arn](#output\_default\_apigatewayv2\_stage\_arn) | The default stage ARN |
|
||||
| <a name="output_default_apigatewayv2_stage_domain_name"></a> [default\_apigatewayv2\_stage\_domain\_name](#output\_default\_apigatewayv2\_stage\_domain\_name) | Domain name of the stage (useful for CloudFront distribution) |
|
||||
| <a name="output_default_apigatewayv2_stage_execution_arn"></a> [default\_apigatewayv2\_stage\_execution\_arn](#output\_default\_apigatewayv2\_stage\_execution\_arn) | The ARN prefix to be used in an aws\_lambda\_permission's source\_arn attribute or in an aws\_iam\_policy to authorize access to the @connections API. |
|
||||
| <a name="output_default_apigatewayv2_stage_id"></a> [default\_apigatewayv2\_stage\_id](#output\_default\_apigatewayv2\_stage\_id) | The default stage identifier |
|
||||
| <a name="output_default_apigatewayv2_stage_invoke_url"></a> [default\_apigatewayv2\_stage\_invoke\_url](#output\_default\_apigatewayv2\_stage\_invoke\_url) | The URL to invoke the API pointing to the stage |
|
||||
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
|
||||
|
||||
## Authors
|
||||
|
||||
Module managed by [Anton Babenko](https://github.com/antonbabenko). Check out [serverless.tf](https://serverless.tf) to learn more about doing serverless with Terraform.
|
||||
|
||||
Please reach out to [Betajob](https://www.betajob.com/) if you are looking for commercial support for your Terraform, AWS, or serverless project.
|
||||
|
||||
## License
|
||||
|
||||
Apache 2 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/tree/master/LICENSE) for full details.
|
||||
@@ -0,0 +1,221 @@
|
||||
# API Gateway
|
||||
resource "aws_apigatewayv2_api" "this" {
|
||||
count = var.create && var.create_api_gateway ? 1 : 0
|
||||
|
||||
name = var.name
|
||||
description = var.description
|
||||
protocol_type = var.protocol_type
|
||||
version = var.api_version
|
||||
body = var.body
|
||||
|
||||
route_selection_expression = var.route_selection_expression
|
||||
api_key_selection_expression = var.api_key_selection_expression
|
||||
disable_execute_api_endpoint = var.disable_execute_api_endpoint
|
||||
fail_on_warnings = var.fail_on_warnings
|
||||
|
||||
/* Start of quick create */
|
||||
route_key = var.route_key
|
||||
credentials_arn = var.credentials_arn
|
||||
target = var.target
|
||||
/* End of quick create */
|
||||
|
||||
dynamic "cors_configuration" {
|
||||
for_each = length(keys(var.cors_configuration)) == 0 ? [] : [var.cors_configuration]
|
||||
|
||||
content {
|
||||
allow_credentials = try(cors_configuration.value.allow_credentials, null)
|
||||
allow_headers = try(cors_configuration.value.allow_headers, null)
|
||||
allow_methods = try(cors_configuration.value.allow_methods, null)
|
||||
allow_origins = try(cors_configuration.value.allow_origins, null)
|
||||
expose_headers = try(cors_configuration.value.expose_headers, null)
|
||||
max_age = try(cors_configuration.value.max_age, null)
|
||||
}
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
# Domain name
|
||||
resource "aws_apigatewayv2_domain_name" "this" {
|
||||
count = var.create && var.create_api_domain_name ? 1 : 0
|
||||
|
||||
domain_name = var.domain_name
|
||||
|
||||
domain_name_configuration {
|
||||
certificate_arn = var.domain_name_certificate_arn
|
||||
ownership_verification_certificate_arn = var.domain_name_ownership_verification_certificate_arn
|
||||
endpoint_type = "REGIONAL"
|
||||
security_policy = "TLS_1_2"
|
||||
}
|
||||
|
||||
dynamic "mutual_tls_authentication" {
|
||||
for_each = length(keys(var.mutual_tls_authentication)) == 0 ? [] : [var.mutual_tls_authentication]
|
||||
|
||||
content {
|
||||
truststore_uri = mutual_tls_authentication.value.truststore_uri
|
||||
truststore_version = try(mutual_tls_authentication.value.truststore_version, null)
|
||||
}
|
||||
}
|
||||
|
||||
tags = merge(var.domain_name_tags, var.tags)
|
||||
}
|
||||
|
||||
# Default stage
|
||||
resource "aws_apigatewayv2_stage" "default" {
|
||||
count = var.create && var.create_default_stage ? 1 : 0
|
||||
|
||||
api_id = aws_apigatewayv2_api.this[0].id
|
||||
name = "$default"
|
||||
auto_deploy = true
|
||||
|
||||
dynamic "access_log_settings" {
|
||||
for_each = var.default_stage_access_log_destination_arn != null && var.default_stage_access_log_format != null ? [true] : []
|
||||
|
||||
content {
|
||||
destination_arn = var.default_stage_access_log_destination_arn
|
||||
format = var.default_stage_access_log_format
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "default_route_settings" {
|
||||
for_each = length(keys(var.default_route_settings)) == 0 ? [] : [var.default_route_settings]
|
||||
|
||||
content {
|
||||
data_trace_enabled = try(default_route_settings.value.data_trace_enabled, false) # supported in Websocket APIGateway only
|
||||
logging_level = try(default_route_settings.value.logging_level, null) # supported in Websocket APIGateway only
|
||||
|
||||
detailed_metrics_enabled = try(default_route_settings.value.detailed_metrics_enabled, false)
|
||||
throttling_burst_limit = try(default_route_settings.value.throttling_burst_limit, null)
|
||||
throttling_rate_limit = try(default_route_settings.value.throttling_rate_limit, null)
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "route_settings" {
|
||||
for_each = { for k, v in var.integrations : k => v if var.create_routes_and_integrations && try(tobool(v.create_route), true) && length(setintersection(["data_trace_enabled", "detailed_metrics_enabled", "logging_level", "throttling_burst_limit", "throttling_rate_limit"], keys(v))) > 0 }
|
||||
|
||||
content {
|
||||
route_key = route_settings.key
|
||||
data_trace_enabled = try(route_settings.value.data_trace_enabled, var.default_route_settings["data_trace_enabled"], false) # supported in Websocket APIGateway only
|
||||
logging_level = try(route_settings.value.logging_level, var.default_route_settings["logging_level"], null) # supported in Websocket APIGateway only
|
||||
|
||||
detailed_metrics_enabled = try(route_settings.value.detailed_metrics_enabled, var.default_route_settings["detailed_metrics_enabled"], false)
|
||||
throttling_burst_limit = try(route_settings.value.throttling_burst_limit, var.default_route_settings["throttling_burst_limit"], null)
|
||||
throttling_rate_limit = try(route_settings.value.throttling_rate_limit, var.default_route_settings["throttling_rate_limit"], null)
|
||||
}
|
||||
}
|
||||
|
||||
tags = merge(var.default_stage_tags, var.tags)
|
||||
|
||||
# Bug in terraform-aws-provider with perpetual diff
|
||||
lifecycle {
|
||||
ignore_changes = [deployment_id]
|
||||
}
|
||||
}
|
||||
|
||||
# Default API mapping
|
||||
resource "aws_apigatewayv2_api_mapping" "this" {
|
||||
count = var.create && var.create_api_domain_name && var.create_default_stage && var.create_default_stage_api_mapping ? 1 : 0
|
||||
|
||||
api_id = aws_apigatewayv2_api.this[0].id
|
||||
domain_name = aws_apigatewayv2_domain_name.this[0].id
|
||||
stage = aws_apigatewayv2_stage.default[0].id
|
||||
}
|
||||
|
||||
# Routes and integrations
|
||||
resource "aws_apigatewayv2_route" "this" {
|
||||
for_each = var.create && var.create_routes_and_integrations ? var.integrations : {}
|
||||
|
||||
api_id = aws_apigatewayv2_api.this[0].id
|
||||
route_key = each.key
|
||||
|
||||
api_key_required = try(each.value.api_key_required, null)
|
||||
authorization_scopes = try(split(",", each.value.authorization_scopes), null)
|
||||
authorization_type = try(each.value.authorization_type, "NONE")
|
||||
authorizer_id = try(aws_apigatewayv2_authorizer.this[each.value.authorizer_key].id, each.value.authorizer_id, null)
|
||||
model_selection_expression = try(each.value.model_selection_expression, null)
|
||||
operation_name = try(each.value.operation_name, null)
|
||||
route_response_selection_expression = try(each.value.route_response_selection_expression, null)
|
||||
target = "integrations/${aws_apigatewayv2_integration.this[each.key].id}"
|
||||
|
||||
# Have been added to the docs. But is WEBSOCKET only(not yet supported)
|
||||
# request_models = try(each.value.request_models, null)
|
||||
}
|
||||
|
||||
resource "aws_apigatewayv2_integration" "this" {
|
||||
for_each = var.create && var.create_routes_and_integrations ? var.integrations : {}
|
||||
|
||||
api_id = aws_apigatewayv2_api.this[0].id
|
||||
description = try(each.value.description, null)
|
||||
|
||||
integration_type = try(each.value.integration_type, try(each.value.lambda_arn, "") != "" ? "AWS_PROXY" : "MOCK")
|
||||
integration_subtype = try(each.value.integration_subtype, null)
|
||||
integration_method = try(each.value.integration_method, try(each.value.integration_subtype, null) == null ? "POST" : null)
|
||||
integration_uri = try(each.value.lambda_arn, try(each.value.integration_uri, null))
|
||||
|
||||
connection_type = try(each.value.connection_type, "INTERNET")
|
||||
connection_id = try(aws_apigatewayv2_vpc_link.this[each.value["vpc_link"]].id, try(each.value.connection_id, null))
|
||||
|
||||
payload_format_version = try(each.value.payload_format_version, null)
|
||||
timeout_milliseconds = try(each.value.timeout_milliseconds, null)
|
||||
passthrough_behavior = try(each.value.passthrough_behavior, null)
|
||||
content_handling_strategy = try(each.value.content_handling_strategy, null)
|
||||
credentials_arn = try(each.value.credentials_arn, null)
|
||||
request_parameters = try(jsondecode(each.value["request_parameters"]), each.value["request_parameters"], null)
|
||||
|
||||
dynamic "tls_config" {
|
||||
for_each = flatten([try(jsondecode(each.value["tls_config"]), each.value["tls_config"], [])])
|
||||
|
||||
content {
|
||||
server_name_to_verify = tls_config.value["server_name_to_verify"]
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "response_parameters" {
|
||||
for_each = flatten([try(jsondecode(each.value["response_parameters"]), each.value["response_parameters"], [])])
|
||||
|
||||
content {
|
||||
status_code = response_parameters.value["status_code"]
|
||||
mappings = response_parameters.value["mappings"]
|
||||
}
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
# Authorizers
|
||||
resource "aws_apigatewayv2_authorizer" "this" {
|
||||
for_each = var.create && var.create_routes_and_integrations ? var.authorizers : {}
|
||||
|
||||
api_id = aws_apigatewayv2_api.this[0].id
|
||||
|
||||
authorizer_type = try(each.value.authorizer_type, null)
|
||||
identity_sources = try(flatten([each.value.identity_sources]), null)
|
||||
name = try(each.value.name, null)
|
||||
authorizer_uri = try(each.value.authorizer_uri, null)
|
||||
authorizer_payload_format_version = try(each.value.authorizer_payload_format_version, null)
|
||||
authorizer_result_ttl_in_seconds = try(each.value.authorizer_result_ttl_in_seconds, null)
|
||||
authorizer_credentials_arn = try(each.value.authorizer_credentials_arn, null)
|
||||
enable_simple_responses = try(each.value.enable_simple_responses, null)
|
||||
|
||||
dynamic "jwt_configuration" {
|
||||
for_each = length(try(each.value.audience, [each.value.issuer], [])) > 0 ? [true] : []
|
||||
|
||||
content {
|
||||
audience = try(each.value.audience, null)
|
||||
issuer = try(each.value.issuer, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# VPC Link (Private API)
|
||||
resource "aws_apigatewayv2_vpc_link" "this" {
|
||||
for_each = var.create && var.create_vpc_link ? var.vpc_links : {}
|
||||
|
||||
name = try(each.value.name, each.key)
|
||||
security_group_ids = each.value["security_group_ids"]
|
||||
subnet_ids = each.value["subnet_ids"]
|
||||
|
||||
tags = merge(var.tags, var.vpc_link_tags, try(each.value.tags, {}))
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
output "apigatewayv2_api_id" {
|
||||
description = "The API identifier"
|
||||
value = try(aws_apigatewayv2_api.this[0].id, "")
|
||||
}
|
||||
|
||||
output "apigatewayv2_api_api_endpoint" {
|
||||
description = "The URI of the API"
|
||||
value = try(aws_apigatewayv2_api.this[0].api_endpoint, "")
|
||||
}
|
||||
|
||||
output "apigatewayv2_api_arn" {
|
||||
description = "The ARN of the API"
|
||||
value = try(aws_apigatewayv2_api.this[0].arn, "")
|
||||
}
|
||||
|
||||
output "apigatewayv2_api_execution_arn" {
|
||||
description = "The ARN prefix to be used in an aws_lambda_permission's source_arn attribute or in an aws_iam_policy to authorize access to the @connections API."
|
||||
value = try(aws_apigatewayv2_api.this[0].execution_arn, "")
|
||||
}
|
||||
|
||||
# default stage
|
||||
output "default_apigatewayv2_stage_id" {
|
||||
description = "The default stage identifier"
|
||||
value = try(aws_apigatewayv2_stage.default[0].id, "")
|
||||
}
|
||||
|
||||
output "default_apigatewayv2_stage_arn" {
|
||||
description = "The default stage ARN"
|
||||
value = try(aws_apigatewayv2_stage.default[0].arn, "")
|
||||
}
|
||||
|
||||
output "default_apigatewayv2_stage_execution_arn" {
|
||||
description = "The ARN prefix to be used in an aws_lambda_permission's source_arn attribute or in an aws_iam_policy to authorize access to the @connections API."
|
||||
value = try(aws_apigatewayv2_stage.default[0].execution_arn, "")
|
||||
}
|
||||
|
||||
output "default_apigatewayv2_stage_invoke_url" {
|
||||
description = "The URL to invoke the API pointing to the stage"
|
||||
value = try(aws_apigatewayv2_stage.default[0].invoke_url, "")
|
||||
}
|
||||
|
||||
output "default_apigatewayv2_stage_domain_name" {
|
||||
description = "Domain name of the stage (useful for CloudFront distribution)"
|
||||
value = replace(try(aws_apigatewayv2_stage.default[0].invoke_url, ""), "/^https?://([^/]*).*/", "$1")
|
||||
}
|
||||
|
||||
# domain name
|
||||
output "apigatewayv2_domain_name_id" {
|
||||
description = "The domain name identifier"
|
||||
value = try(aws_apigatewayv2_domain_name.this[0].id, "")
|
||||
}
|
||||
|
||||
output "apigatewayv2_domain_name_arn" {
|
||||
description = "The ARN of the domain name"
|
||||
value = try(aws_apigatewayv2_domain_name.this[0].arn, "")
|
||||
}
|
||||
|
||||
output "apigatewayv2_domain_name_api_mapping_selection_expression" {
|
||||
description = "The API mapping selection expression for the domain name"
|
||||
value = try(aws_apigatewayv2_domain_name.this[0].api_mapping_selection_expression, "")
|
||||
}
|
||||
|
||||
output "apigatewayv2_domain_name_configuration" {
|
||||
description = "The domain name configuration"
|
||||
value = try(aws_apigatewayv2_domain_name.this[0].domain_name_configuration, "")
|
||||
}
|
||||
|
||||
output "apigatewayv2_domain_name_target_domain_name" {
|
||||
description = "The target domain name"
|
||||
value = try(aws_apigatewayv2_domain_name.this[0].domain_name_configuration[0].target_domain_name, "")
|
||||
}
|
||||
|
||||
output "apigatewayv2_domain_name_hosted_zone_id" {
|
||||
description = "The Amazon Route 53 Hosted Zone ID of the endpoint"
|
||||
value = try(aws_apigatewayv2_domain_name.this[0].domain_name_configuration[0].hosted_zone_id, "")
|
||||
}
|
||||
|
||||
# api mapping
|
||||
output "apigatewayv2_api_mapping_id" {
|
||||
description = "The API mapping identifier."
|
||||
value = try(aws_apigatewayv2_api_mapping.this[0].id, "")
|
||||
}
|
||||
|
||||
# route
|
||||
# output "apigatewayv2_route_id" {
|
||||
# description = "The default route identifier."
|
||||
# value = try(aws_apigatewayv2_route.this[0].id, "")
|
||||
# }
|
||||
|
||||
# VPC link
|
||||
output "apigatewayv2_vpc_link_id" {
|
||||
description = "The map of VPC Link identifiers"
|
||||
value = { for k, v in aws_apigatewayv2_vpc_link.this : k => v.id }
|
||||
}
|
||||
|
||||
output "apigatewayv2_vpc_link_arn" {
|
||||
description = "The map of VPC Link ARNs"
|
||||
value = { for k, v in aws_apigatewayv2_vpc_link.this : k => v.arn }
|
||||
}
|
||||
|
||||
output "apigatewayv2_authorizer_id" {
|
||||
description = "The map of API Gateway Authorizer identifiers"
|
||||
value = { for k, v in aws_apigatewayv2_authorizer.this : k => v.id }
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
variable "create" {
|
||||
description = "Controls if API Gateway resources should be created"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "create_api_gateway" {
|
||||
description = "Whether to create API Gateway"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "create_default_stage" {
|
||||
description = "Whether to create default stage"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "create_default_stage_api_mapping" {
|
||||
description = "Whether to create default stage API mapping"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
# variable "create_stage" {
|
||||
# description = "Whether to create custom stage"
|
||||
# type = bool
|
||||
# default = false
|
||||
# }
|
||||
#
|
||||
# variable "create_stage_api_mapping" {
|
||||
# description = "Whether to create stage API mapping"
|
||||
# type = bool
|
||||
# default = false
|
||||
# }
|
||||
|
||||
variable "create_api_domain_name" {
|
||||
description = "Whether to create API domain name resource"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "create_routes_and_integrations" {
|
||||
description = "Whether to create routes and integrations resources"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "create_vpc_link" {
|
||||
description = "Whether to create VPC links"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
# API Gateway
|
||||
variable "name" {
|
||||
description = "The name of the API"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "description" {
|
||||
description = "The description of the API."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "default_route_settings" {
|
||||
description = "Settings for default route"
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "disable_execute_api_endpoint" {
|
||||
description = "Whether clients can invoke the API by using the default execute-api endpoint. To require that clients use a custom domain name to invoke the API, disable the default endpoint"
|
||||
type = string
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "fail_on_warnings" {
|
||||
description = "Whether warnings should return an error while API Gateway is creating or updating the resource using an OpenAPI specification. Defaults to false. Applicable for HTTP APIs."
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "protocol_type" {
|
||||
description = "The API protocol. Valid values: HTTP, WEBSOCKET"
|
||||
type = string
|
||||
default = "HTTP"
|
||||
}
|
||||
|
||||
variable "api_key_selection_expression" {
|
||||
description = "An API key selection expression. Valid values: $context.authorizer.usageIdentifierKey, $request.header.x-api-key."
|
||||
type = string
|
||||
default = "$request.header.x-api-key"
|
||||
}
|
||||
|
||||
variable "route_key" {
|
||||
description = "Part of quick create. Specifies any route key. Applicable for HTTP APIs."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "route_selection_expression" {
|
||||
description = "The route selection expression for the API."
|
||||
type = string
|
||||
default = "$request.method $request.path"
|
||||
}
|
||||
|
||||
variable "cors_configuration" {
|
||||
description = "The cross-origin resource sharing (CORS) configuration. Applicable for HTTP APIs."
|
||||
type = any
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "credentials_arn" {
|
||||
description = "Part of quick create. Specifies any credentials required for the integration. Applicable for HTTP APIs."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "target" {
|
||||
description = "Part of quick create. Quick create produces an API with an integration, a default catch-all route, and a default stage which is configured to automatically deploy changes. For HTTP integrations, specify a fully qualified URL. For Lambda integrations, specify a function ARN. The type of the integration will be HTTP_PROXY or AWS_PROXY, respectively. Applicable for HTTP APIs."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "body" {
|
||||
description = "An OpenAPI specification that defines the set of routes and integrations to create as part of the HTTP APIs. Supported only for HTTP APIs."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "api_version" {
|
||||
description = "A version identifier for the API"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
description = "A mapping of tags to assign to API gateway resources."
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
#####
|
||||
# default stage
|
||||
variable "default_stage_access_log_destination_arn" {
|
||||
description = "Default stage's ARN of the CloudWatch Logs log group to receive access logs. Any trailing :* is trimmed from the ARN."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "default_stage_access_log_format" {
|
||||
description = "Default stage's single line format of the access logs of data, as specified by selected $context variables."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "default_stage_tags" {
|
||||
description = "A mapping of tags to assign to the default stage resource."
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
#####
|
||||
# default stage API mapping
|
||||
|
||||
####
|
||||
# domain name
|
||||
variable "domain_name" {
|
||||
description = "The domain name to use for API gateway"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "domain_name_certificate_arn" {
|
||||
description = "The ARN of an AWS-managed certificate that will be used by the endpoint for the domain name"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "domain_name_ownership_verification_certificate_arn" {
|
||||
description = "ARN of the AWS-issued certificate used to validate custom domain ownership (when certificate_arn is issued via an ACM Private CA or mutual_tls_authentication is configured with an ACM-imported certificate.)"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "domain_name_tags" {
|
||||
description = "A mapping of tags to assign to API domain name resource."
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "mutual_tls_authentication" {
|
||||
description = "An Amazon S3 URL that specifies the truststore for mutual TLS authentication as well as version, keyed at uri and version"
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
####
|
||||
# routes and integrations
|
||||
variable "integrations" {
|
||||
description = "Map of API gateway routes with integrations"
|
||||
type = map(any)
|
||||
default = {}
|
||||
}
|
||||
|
||||
# authorrizers
|
||||
variable "authorizers" {
|
||||
description = "Map of API gateway authorizers"
|
||||
type = map(any)
|
||||
default = {}
|
||||
}
|
||||
|
||||
# vpc link
|
||||
variable "vpc_links" {
|
||||
description = "Map of VPC Links details to create"
|
||||
type = map(any)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "vpc_link_tags" {
|
||||
description = "A map of tags to add to the VPC Link"
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
terraform {
|
||||
required_version = ">= 1.0"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
# Wrapper for the root module
|
||||
|
||||
The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt).
|
||||
|
||||
You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module.
|
||||
|
||||
This wrapper does not implement any extra functionality.
|
||||
|
||||
## Usage with Terragrunt
|
||||
|
||||
`terragrunt.hcl`:
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
source = "tfr:///terraform-aws-modules/apigateway-v2/aws//wrappers"
|
||||
# Alternative source:
|
||||
# source = "git::git@github.com:terraform-aws-modules/terraform-aws-apigateway-v2.git//wrappers?ref=master"
|
||||
}
|
||||
|
||||
inputs = {
|
||||
defaults = { # Default values
|
||||
create = true
|
||||
tags = {
|
||||
Terraform = "true"
|
||||
Environment = "dev"
|
||||
}
|
||||
}
|
||||
|
||||
items = {
|
||||
my-item = {
|
||||
# omitted... can be any argument supported by the module
|
||||
}
|
||||
my-second-item = {
|
||||
# omitted... can be any argument supported by the module
|
||||
}
|
||||
# omitted...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage with Terraform
|
||||
|
||||
```hcl
|
||||
module "wrapper" {
|
||||
source = "terraform-aws-modules/apigateway-v2/aws//wrappers"
|
||||
|
||||
defaults = { # Default values
|
||||
create = true
|
||||
tags = {
|
||||
Terraform = "true"
|
||||
Environment = "dev"
|
||||
}
|
||||
}
|
||||
|
||||
items = {
|
||||
my-item = {
|
||||
# omitted... can be any argument supported by the module
|
||||
}
|
||||
my-second-item = {
|
||||
# omitted... can be any argument supported by the module
|
||||
}
|
||||
# omitted...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example: Manage multiple S3 buckets in one Terragrunt layer
|
||||
|
||||
`eu-west-1/s3-buckets/terragrunt.hcl`:
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers"
|
||||
# Alternative source:
|
||||
# source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers?ref=master"
|
||||
}
|
||||
|
||||
inputs = {
|
||||
defaults = {
|
||||
force_destroy = true
|
||||
|
||||
attach_elb_log_delivery_policy = true
|
||||
attach_lb_log_delivery_policy = true
|
||||
attach_deny_insecure_transport_policy = true
|
||||
attach_require_latest_tls_policy = true
|
||||
}
|
||||
|
||||
items = {
|
||||
bucket1 = {
|
||||
bucket = "my-random-bucket-1"
|
||||
}
|
||||
bucket2 = {
|
||||
bucket = "my-random-bucket-2"
|
||||
tags = {
|
||||
Secure = "probably"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,40 @@
|
||||
module "wrapper" {
|
||||
source = "../"
|
||||
|
||||
for_each = var.items
|
||||
|
||||
api_key_selection_expression = try(each.value.api_key_selection_expression, var.defaults.api_key_selection_expression, "$request.header.x-api-key")
|
||||
api_version = try(each.value.api_version, var.defaults.api_version, null)
|
||||
authorizers = try(each.value.authorizers, var.defaults.authorizers, {})
|
||||
body = try(each.value.body, var.defaults.body, null)
|
||||
cors_configuration = try(each.value.cors_configuration, var.defaults.cors_configuration, {})
|
||||
create = try(each.value.create, var.defaults.create, true)
|
||||
create_api_domain_name = try(each.value.create_api_domain_name, var.defaults.create_api_domain_name, true)
|
||||
create_api_gateway = try(each.value.create_api_gateway, var.defaults.create_api_gateway, true)
|
||||
create_default_stage = try(each.value.create_default_stage, var.defaults.create_default_stage, true)
|
||||
create_default_stage_api_mapping = try(each.value.create_default_stage_api_mapping, var.defaults.create_default_stage_api_mapping, true)
|
||||
create_routes_and_integrations = try(each.value.create_routes_and_integrations, var.defaults.create_routes_and_integrations, true)
|
||||
create_vpc_link = try(each.value.create_vpc_link, var.defaults.create_vpc_link, true)
|
||||
credentials_arn = try(each.value.credentials_arn, var.defaults.credentials_arn, null)
|
||||
default_route_settings = try(each.value.default_route_settings, var.defaults.default_route_settings, {})
|
||||
default_stage_access_log_destination_arn = try(each.value.default_stage_access_log_destination_arn, var.defaults.default_stage_access_log_destination_arn, null)
|
||||
default_stage_access_log_format = try(each.value.default_stage_access_log_format, var.defaults.default_stage_access_log_format, null)
|
||||
default_stage_tags = try(each.value.default_stage_tags, var.defaults.default_stage_tags, {})
|
||||
description = try(each.value.description, var.defaults.description, null)
|
||||
disable_execute_api_endpoint = try(each.value.disable_execute_api_endpoint, var.defaults.disable_execute_api_endpoint, false)
|
||||
domain_name = try(each.value.domain_name, var.defaults.domain_name, null)
|
||||
domain_name_certificate_arn = try(each.value.domain_name_certificate_arn, var.defaults.domain_name_certificate_arn, null)
|
||||
domain_name_ownership_verification_certificate_arn = try(each.value.domain_name_ownership_verification_certificate_arn, var.defaults.domain_name_ownership_verification_certificate_arn, null)
|
||||
domain_name_tags = try(each.value.domain_name_tags, var.defaults.domain_name_tags, {})
|
||||
fail_on_warnings = try(each.value.fail_on_warnings, var.defaults.fail_on_warnings, false)
|
||||
integrations = try(each.value.integrations, var.defaults.integrations, {})
|
||||
mutual_tls_authentication = try(each.value.mutual_tls_authentication, var.defaults.mutual_tls_authentication, {})
|
||||
name = try(each.value.name, var.defaults.name, "")
|
||||
protocol_type = try(each.value.protocol_type, var.defaults.protocol_type, "HTTP")
|
||||
route_key = try(each.value.route_key, var.defaults.route_key, null)
|
||||
route_selection_expression = try(each.value.route_selection_expression, var.defaults.route_selection_expression, "$request.method $request.path")
|
||||
tags = try(each.value.tags, var.defaults.tags, {})
|
||||
target = try(each.value.target, var.defaults.target, null)
|
||||
vpc_link_tags = try(each.value.vpc_link_tags, var.defaults.vpc_link_tags, {})
|
||||
vpc_links = try(each.value.vpc_links, var.defaults.vpc_links, {})
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
output "wrapper" {
|
||||
description = "Map of outputs of a wrapper."
|
||||
value = module.wrapper
|
||||
# sensitive = false # No sensitive module output found
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
variable "defaults" {
|
||||
description = "Map of default values which will be used for each item."
|
||||
type = any
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "items" {
|
||||
description = "Maps of items to create a wrapper from. Values are passed through to the module."
|
||||
type = any
|
||||
default = {}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
terraform {
|
||||
required_version = ">= 0.13.1"
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<!-- This readme file is generated with terraform-docs -->
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | >= 1.3.0 |
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_sesv2_configuration_set.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sesv2_configuration_set) | resource |
|
||||
| [aws_sesv2_email_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sesv2_email_identity) | resource |
|
||||
| [aws_sesv2_email_identity_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sesv2_email_identity_policy) | resource |
|
||||
| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
|
||||
| [aws_iam_policy_document.ses-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| emails | Email addresses to be added to SES | `list(string)` | n/a | yes |
|
||||
| reputation\_metrics\_enabled | Enable reputation metrics | `bool` | `true` | no |
|
||||
|
||||
## Outputs
|
||||
|
||||
No outputs.
|
||||
|
||||
---
|
||||
## Authorship
|
||||
This module was developed by UPDATE_THIS.
|
||||
@@ -0,0 +1,63 @@
|
||||
data "aws_caller_identity" "this" {}
|
||||
data "aws_region" "this" {}
|
||||
|
||||
resource "aws_sesv2_email_identity" "this" {
|
||||
for_each = toset(var.emails)
|
||||
email_identity = each.value
|
||||
configuration_set_name = aws_sesv2_configuration_set.this.configuration_set_name
|
||||
}
|
||||
|
||||
resource "aws_sesv2_configuration_set" "this" {
|
||||
configuration_set_name = "default-sesv2-configuration-set"
|
||||
|
||||
delivery_options {
|
||||
tls_policy = var.require_tls ? "REQUIRE" : "OPTIONAL"
|
||||
}
|
||||
|
||||
reputation_options {
|
||||
reputation_metrics_enabled = var.reputation_metrics_enabled
|
||||
}
|
||||
|
||||
sending_options {
|
||||
sending_enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
# The exact same policy can be created successfully on console!
|
||||
#resource "aws_sesv2_email_identity_policy" "this" {
|
||||
# for_each = aws_sesv2_email_identity.this
|
||||
# email_identity = each.value.arn
|
||||
# policy_name = "default-policy"
|
||||
# # policy = data.aws_iam_policy_document.ses-policy[each.key].json
|
||||
# policy = jsonencode({
|
||||
# "Version" : "2012-10-17",
|
||||
# "Statement" : [
|
||||
# {
|
||||
# "Sid" : "default",
|
||||
# "Effect" : "Allow",
|
||||
# "Principal" : {
|
||||
# "AWS" : "arn:aws:iam::${data.aws_caller_identity.this.account_id}:root"
|
||||
# },
|
||||
# "Action" : [
|
||||
# "ses:SendEmail",
|
||||
# "ses:SendRawEmail"
|
||||
# ],
|
||||
# "Resource" : each.value.arn,
|
||||
# "Condition" : {}
|
||||
# }
|
||||
# ]
|
||||
# })
|
||||
#}
|
||||
|
||||
#data "aws_iam_policy_document" "ses-policy" {
|
||||
# for_each = aws_sesv2_email_identity.this
|
||||
# statement {
|
||||
# sid = "default"
|
||||
# actions = ["SES:SendEmail", "SES:SendRawEmail"]
|
||||
# resources = [each.value.arn]
|
||||
# principals {
|
||||
# identifiers = [data.aws_caller_identity.this.account_id]
|
||||
# type = "AWS"
|
||||
# }
|
||||
# }
|
||||
#}
|
||||
@@ -0,0 +1,16 @@
|
||||
variable "emails" {
|
||||
type = list(string)
|
||||
description = "Email addresses to be added to SES"
|
||||
}
|
||||
|
||||
variable "reputation_metrics_enabled" {
|
||||
type = bool
|
||||
description = "Enable reputation metrics"
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "require_tls" {
|
||||
type = bool
|
||||
description = "Require TLS delivery option"
|
||||
default = true
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = ">= 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.0, < 5.39"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<!-- This readme file is generated with terraform-docs -->
|
||||
This module installs Cloudwatch agent via SSM State Manager.
|
||||
It creates an association and install the agent to all instances every 1 day.
|
||||
|
||||
Then a default cloudwatch agent config is generated using amazon-cloudwatch-agent-config-wizard,
|
||||
saved on /opt/aws/amazon-cloudwatch-agent/bin/config.json, supplemented with additional collections,
|
||||
and uploaded on SSM parameter store as ```AmazonCloudWatch-linux```.
|
||||
|
||||
Note that for cloudwatch agent to fully function, the instance needs an instance profile with the
|
||||
following managed policies attached:
|
||||
|
||||
* CloudWatchAgentServerPolicy
|
||||
* AmazonSSMManagedInstanceCore
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | >= 1.3.0 |
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_ssm_association.ConfigCwAgent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_association) | resource |
|
||||
| [aws_ssm_association.InstallCwAgent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_association) | resource |
|
||||
| [aws_ssm_parameter.CwAgentConfigLinux](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter) | resource |
|
||||
|
||||
## Inputs
|
||||
|
||||
No inputs.
|
||||
|
||||
## Outputs
|
||||
|
||||
No outputs.
|
||||
|
||||
---
|
||||
## Authorship
|
||||
This module was developed by UPDATE_THIS.
|
||||
@@ -0,0 +1,135 @@
|
||||
resource "aws_ssm_association" "InstallCwAgent" {
|
||||
name = "AWS-ConfigureAWSPackage"
|
||||
association_name = "CwAgentInstall"
|
||||
schedule_expression = "cron(0 00 01 ? * * *)"
|
||||
max_concurrency = 10
|
||||
parameters = {
|
||||
name = "AmazonCloudWatchAgent"
|
||||
action = "Install"
|
||||
installationType = "Uninstall and reinstall"
|
||||
additionalArguments = "{}"
|
||||
}
|
||||
targets {
|
||||
key = "InstanceIds"
|
||||
values = ["*"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_ssm_association" "ConfigCwAgent" {
|
||||
name = "AmazonCloudWatch-ManageAgent"
|
||||
association_name = "CwAgentConfiguration"
|
||||
schedule_expression = "cron(0 00 02 ? * * *)"
|
||||
max_concurrency = 10
|
||||
parameters = {
|
||||
action = "configure"
|
||||
optionalConfigurationLocation = "AmazonCloudWatch-linux"
|
||||
optionalConfigurationSource = "ssm"
|
||||
mode = "ec2"
|
||||
optionalRestart = "yes"
|
||||
}
|
||||
targets {
|
||||
key = "InstanceIds"
|
||||
values = ["*"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_ssm_parameter" "CwAgentConfigLinux" {
|
||||
name = "AmazonCloudWatch-linux"
|
||||
description = "Cloudwatch agent Standard config for Linux"
|
||||
type = "String"
|
||||
value = local.CwAgentLinuxConfig
|
||||
}
|
||||
|
||||
locals {
|
||||
CwAgentLinuxConfig = jsonencode(
|
||||
{
|
||||
"agent" : {
|
||||
"metrics_collection_interval" : 60,
|
||||
"run_as_user" : "root"
|
||||
},
|
||||
"metrics" : {
|
||||
"aggregation_dimensions" : [
|
||||
[
|
||||
"InstanceId"
|
||||
]
|
||||
],
|
||||
"append_dimensions" : {
|
||||
"AutoScalingGroupName" : "$${aws:AutoScalingGroupName}",
|
||||
"ImageId" : "$${aws:ImageId}",
|
||||
"InstanceId" : "$${aws:InstanceId}",
|
||||
"InstanceType" : "$${aws:InstanceType}"
|
||||
},
|
||||
"metrics_collected" : {
|
||||
"cpu" : {
|
||||
"measurement" : [
|
||||
"cpu_usage_idle",
|
||||
"cpu_usage_iowait",
|
||||
"cpu_usage_user",
|
||||
"cpu_usage_system"
|
||||
],
|
||||
"metrics_collection_interval" : 60,
|
||||
"resources" : [
|
||||
"*"
|
||||
],
|
||||
"totalcpu" : false
|
||||
},
|
||||
"disk" : {
|
||||
"measurement" : [
|
||||
"used_percent",
|
||||
"inodes_free"
|
||||
],
|
||||
"metrics_collection_interval" : 60,
|
||||
"resources" : [
|
||||
"*"
|
||||
],
|
||||
"ignore_file_system_types" : [
|
||||
"devtmpfs",
|
||||
"overlay",
|
||||
"sysfs",
|
||||
"tmpfs"
|
||||
]
|
||||
},
|
||||
"diskio" : {
|
||||
"measurement" : [
|
||||
"io_time"
|
||||
],
|
||||
"metrics_collection_interval" : 60,
|
||||
"resources" : [
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"mem" : {
|
||||
"measurement" : [
|
||||
"mem_used_percent"
|
||||
],
|
||||
"metrics_collection_interval" : 60
|
||||
},
|
||||
"statsd" : {
|
||||
"metrics_aggregation_interval" : 60,
|
||||
"metrics_collection_interval" : 10,
|
||||
"service_address" : ":8125"
|
||||
},
|
||||
"swap" : {
|
||||
"measurement" : [
|
||||
"swap_used_percent"
|
||||
],
|
||||
"metrics_collection_interval" : 60
|
||||
},
|
||||
"net": {
|
||||
"measurement": [
|
||||
"net_err_in",
|
||||
"net_err_out"
|
||||
],
|
||||
"metrics_collection_interval": 60
|
||||
},
|
||||
"processes": {
|
||||
"measurement": [
|
||||
"processes_total"
|
||||
],
|
||||
"metrics_collection_interval": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = ">= 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<!-- This readme file is generated with terraform-docs -->
|
||||
|
||||
This module configure CloudwatchLog and stream logs to s3 bucket via Kinesis Firehose
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | ~> 1.3.0 |
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| aws | >= 5.0 |
|
||||
| random | n/a |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_cloudwatch_log_group.firehose-log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
|
||||
| [aws_cloudwatch_log_subscription_filter.cwl-sub-filter](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_subscription_filter) | resource |
|
||||
| [aws_iam_policy.cwlog-role-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
|
||||
| [aws_iam_policy.firehose-role-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
|
||||
| [aws_iam_role.cwlog-stream-role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
|
||||
| [aws_iam_role.firehose-stream-iam-role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
|
||||
| [aws_iam_role_policy_attachment.cwlog-role-policy-attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
|
||||
| [aws_iam_role_policy_attachment.firehose-role-policy-attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
|
||||
| [aws_kinesis_firehose_delivery_stream.cwl-s3-firehose-stream](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kinesis_firehose_delivery_stream) | resource |
|
||||
| [random_id.rid](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
|
||||
| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| cwl-region | AWS region where Cloudwatch LogGroup resides. Needed for setting up cwlog-stream-role | `string` | n/a | yes |
|
||||
| dest-bucket-arn | Destination S3 bucket ARN | `string` | n/a | yes |
|
||||
| dest-bucket-kmskey-arn | KMS key ARN for destination bucket | `string` | n/a | yes |
|
||||
| dest-bucket-prefix | S3 object prefix for this stream. Please do not start with / end with a /. For example, r53-log/acme.local/ | `string` | n/a | yes |
|
||||
| enable-firehose-errorlog | Enable firehose errorlog | `bool` | `false` | no |
|
||||
| firehose-kmskey-arn | KMS Key arn for Firehose | `string` | n/a | yes |
|
||||
| source-cwlgroup-name | Name of source CloudwatchLog group | `string` | n/a | yes |
|
||||
| stream-name | Name of Kinesis Data Firehose delivery stream | `string` | n/a | yes |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| cloudwatchstream-iam-role-arn | n/a |
|
||||
| firehose-iam-role-arn | n/a |
|
||||
|
||||
---
|
||||
## Authorship
|
||||
This module was developed by Rackspace.
|
||||
@@ -0,0 +1,162 @@
|
||||
resource "aws_kinesis_firehose_delivery_stream" "cwl-s3-firehose-stream" {
|
||||
name = var.stream-name
|
||||
destination = "extended_s3"
|
||||
|
||||
extended_s3_configuration {
|
||||
role_arn = aws_iam_role.firehose-stream-iam-role.arn
|
||||
bucket_arn = var.dest-bucket-arn
|
||||
prefix = trimprefix(var.dest-bucket-prefix, "/")
|
||||
error_output_prefix = "FirehoseErrors/"
|
||||
kms_key_arn = var.dest-bucket-kmskey-arn
|
||||
compression_format = "GZIP"
|
||||
cloudwatch_logging_options {
|
||||
enabled = var.enable-firehose-errorlog
|
||||
log_group_name = try(aws_cloudwatch_log_group.firehose-log[0].name, null)
|
||||
log_stream_name = "DestinationDelivery"
|
||||
}
|
||||
}
|
||||
server_side_encryption {
|
||||
enabled = true
|
||||
key_type = "CUSTOMER_MANAGED_CMK"
|
||||
key_arn = var.firehose-kmskey-arn
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_log_group" "firehose-log" {
|
||||
count = var.enable-firehose-errorlog ? 1 : 0
|
||||
name = "/aws/kinesisfirehose/${var.stream-name}"
|
||||
retention_in_days = 365
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_log_subscription_filter" "cwl-sub-filter" {
|
||||
log_group_name = var.source-cwlgroup-name
|
||||
name = "stream-to-s3"
|
||||
role_arn = aws_iam_role.cwlog-stream-role.arn
|
||||
filter_pattern = ""
|
||||
destination_arn = aws_kinesis_firehose_delivery_stream.cwl-s3-firehose-stream.arn
|
||||
}
|
||||
|
||||
resource "random_id" "rid" {
|
||||
byte_length = 4
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "firehose-stream-iam-role" {
|
||||
name = "firehose-stream-role-${var.stream-name}-${random_id.rid.dec}"
|
||||
description = "Kinesis Firehose IAM role for streaming logs from CloudwatchLog to S3"
|
||||
assume_role_policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "FirehoseStreaming",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"Service" : "firehose.amazonaws.com"
|
||||
},
|
||||
"Action" : "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy_attachment" "firehose-role-policy-attachment" {
|
||||
role = aws_iam_role.firehose-stream-iam-role.name
|
||||
policy_arn = aws_iam_policy.firehose-role-policy.arn
|
||||
}
|
||||
|
||||
resource "aws_iam_policy" "firehose-role-policy" {
|
||||
name = "kinesis-firehose-log-stream-${var.stream-name}-${random_id.rid.dec}"
|
||||
description = "Policy for Kinesis Firehose streaming logs to s3"
|
||||
policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Effect" : "Allow",
|
||||
"Action" : [
|
||||
"s3:AbortMultipartUpload",
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject",
|
||||
"s3:ListBucket",
|
||||
"s3:ListBucketMultipartUploads",
|
||||
"s3:PutObject"
|
||||
],
|
||||
"Resource" : [
|
||||
var.dest-bucket-arn,
|
||||
"${var.dest-bucket-arn}/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Effect" : "Allow",
|
||||
"Action" : [
|
||||
"kms:Decrypt",
|
||||
"kms:GenerateDataKey"
|
||||
],
|
||||
"Resource" : [
|
||||
var.dest-bucket-kmskey-arn
|
||||
]
|
||||
},
|
||||
{
|
||||
"Effect" : "Allow",
|
||||
"Action" : [
|
||||
"logs:PutLogEvents",
|
||||
"logs:PutLogEventsBatch",
|
||||
"logs:CreateLogStream"
|
||||
],
|
||||
"Resource" : [
|
||||
"arn:aws:logs:*:*:log-group:/aws/kinesisfirehose/${var.stream-name}/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
resource "aws_iam_role" "cwlog-stream-role" {
|
||||
name = "cloudwatchlog-stream-role-${var.stream-name}-${random_id.rid.dec}"
|
||||
description = "CloudwatchLog role for streaming to firehose"
|
||||
assume_role_policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "CloudwatchLogStreaming",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"Service" : "logs.${var.cwl-region}.amazonaws.com"
|
||||
},
|
||||
"Action" : "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
resource "aws_iam_role_policy_attachment" "cwlog-role-policy-attachment" {
|
||||
role = aws_iam_role.cwlog-stream-role.name
|
||||
policy_arn = aws_iam_policy.cwlog-role-policy.arn
|
||||
}
|
||||
|
||||
resource "aws_iam_policy" "cwlog-role-policy" {
|
||||
name = "cloudwatchlog-stream-${var.stream-name}-${random_id.rid.dec}"
|
||||
description = "Policy for CloudWatch Logs streaming to Kinesis Firehose"
|
||||
policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Effect" : "Allow",
|
||||
"Action" : ["firehose:PutRecord"],
|
||||
"Resource" : [
|
||||
"arn:aws:firehose:${var.cwl-region}:${data.aws_caller_identity.this.account_id}:deliverystream/${var.stream-name}"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
data "aws_caller_identity" "this" {}
|
||||
@@ -0,0 +1,7 @@
|
||||
output firehose-iam-role-arn {
|
||||
value = aws_iam_role.firehose-stream-iam-role.arn
|
||||
}
|
||||
|
||||
output cloudwatchstream-iam-role-arn {
|
||||
value = aws_iam_role.cwlog-stream-role.arn
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
variable "stream-name" {
|
||||
type = string
|
||||
description = "Name of Kinesis Data Firehose delivery stream"
|
||||
}
|
||||
|
||||
variable "firehose-kmskey-arn" {
|
||||
type = string
|
||||
description = "KMS Key arn for Firehose"
|
||||
}
|
||||
|
||||
variable "dest-bucket-arn" {
|
||||
type = string
|
||||
description = "Destination S3 bucket ARN"
|
||||
}
|
||||
|
||||
variable "dest-bucket-prefix" {
|
||||
type = string
|
||||
description = "S3 object prefix for this stream. Please do not start with / end with a /. For example, r53-log/acme.local/"
|
||||
}
|
||||
|
||||
variable "dest-bucket-kmskey-arn" {
|
||||
type = string
|
||||
description = "KMS key ARN for destination bucket"
|
||||
}
|
||||
|
||||
variable "source-cwlgroup-name" {
|
||||
type = string
|
||||
description = "Name of source CloudwatchLog group"
|
||||
}
|
||||
|
||||
variable "cwl-region" {
|
||||
type = string
|
||||
description = "AWS region where Cloudwatch LogGroup resides. Needed for setting up cwlog-stream-role"
|
||||
}
|
||||
|
||||
variable "enable-firehose-errorlog" {
|
||||
type = bool
|
||||
description = "Enable firehose errorlog"
|
||||
default = false
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "alb-arns" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "alb"
|
||||
}
|
||||
|
||||
module "alb-monitoring" {
|
||||
for_each = toset(split(" ", data.external.alb-arns.result.result))
|
||||
source = "../../modules/ManagementGovernance/Monitoring.ALB"
|
||||
default-tags = local.default-tags
|
||||
load-balancer = each.value
|
||||
threshold-HealthHostCountMin = 1
|
||||
}
|
||||
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
eval "$(jq -r '@sh "lb=\(.lb)"')"
|
||||
|
||||
RESULTS=$(aws elbv2 describe-target-groups --load-balancer-arn $lb --query TargetGroups[*].TargetGroupArn --output text --no-cli-pager | sed 's/\t/\n/g' | sort | xargs)
|
||||
jq -n --arg result "$RESULTS" '{"result":$result}'
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
locals {
|
||||
alb-name = "app/${split("/", var.load-balancer)[2]}/${split("/", var.load-balancer)[3]}"
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "alb-HTTPCode_ELB_5XX_Count" {
|
||||
alarm_name = "${var.settings.HTTPCode_ELB_5XX_Count.ecccode}-ALB_${local.alb-name}-HTTPCode_ELB_5XX_Count"
|
||||
comparison_operator = var.settings.HTTPCode_ELB_5XX_Count.comparison_operator
|
||||
evaluation_periods = var.settings.HTTPCode_ELB_5XX_Count.evaluation_periods
|
||||
metric_name = "HTTPCode_ELB_5XX_Count"
|
||||
period = var.settings.HTTPCode_ELB_5XX_Count.period
|
||||
statistic = var.settings.HTTPCode_ELB_5XX_Count.statistic
|
||||
threshold = var.settings.HTTPCode_ELB_5XX_Count.threshold
|
||||
alarm_description = "ALB:HTTPCode_ELB_5XX_Count"
|
||||
namespace = "AWS/ApplicationELB"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.HTTPCode_ELB_5XX_Count.action]
|
||||
ok_actions = [var.settings.HTTPCode_ELB_5XX_Count.action]
|
||||
dimensions = {
|
||||
LoadBalancer = local.alb-name
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "alb-TargetConnectionErrorCount" {
|
||||
alarm_name = "${var.settings.TargetConnectionErrorCount.ecccode}-ALB_${local.alb-name}-TargetConnectionErrorCount"
|
||||
comparison_operator = var.settings.TargetConnectionErrorCount.comparison_operator
|
||||
evaluation_periods = var.settings.TargetConnectionErrorCount.evaluation_periods
|
||||
metric_name = "TargetConnectionErrorCount"
|
||||
period = var.settings.TargetConnectionErrorCount.period
|
||||
statistic = var.settings.TargetConnectionErrorCount.statistic
|
||||
threshold = var.settings.TargetConnectionErrorCount.threshold
|
||||
alarm_description = "ALB:TargetConnectionErrorCount"
|
||||
namespace = "AWS/ApplicationELB"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.TargetConnectionErrorCount.action]
|
||||
ok_actions = [var.settings.TargetConnectionErrorCount.action]
|
||||
dimensions = {
|
||||
LoadBalancer = local.alb-name
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "alb-TargetResponseTime" {
|
||||
alarm_name = "${var.settings.TargetResponseTime.ecccode}-ALB_${local.alb-name}-TargetResponseTime"
|
||||
comparison_operator = var.settings.TargetResponseTime.comparison_operator
|
||||
evaluation_periods = var.settings.TargetResponseTime.evaluation_periods
|
||||
metric_name = "TargetResponseTime"
|
||||
period = var.settings.TargetResponseTime.period
|
||||
statistic = var.settings.TargetResponseTime.statistic
|
||||
threshold = var.settings.TargetResponseTime.threshold
|
||||
alarm_description = "ALB:TargetResponseTime"
|
||||
namespace = "AWS/ApplicationELB"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.TargetResponseTime.action]
|
||||
ok_actions = [var.settings.TargetResponseTime.action]
|
||||
dimensions = {
|
||||
LoadBalancer = local.alb-name
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
module "alb-targetgroups" {
|
||||
source = "../../util/resource-list"
|
||||
resource-type = "alb-targetgroups"
|
||||
query-input = var.load-balancer
|
||||
asrolearn = var.asrolearn
|
||||
}
|
||||
*/
|
||||
// causes Rate exceeded error, maybe because of adaptive AWS_RETRY_MODE?
|
||||
|
||||
/*
|
||||
module "alb_tgs" {
|
||||
assume_role_arn = var.asrolearn
|
||||
role_session_name = "terraform-resource-list"
|
||||
source = "../../util/terraform-aws-cli"
|
||||
aws_cli_commands = ["elbv2", "describe-target-groups", "--load-balancer-arn", var.load-balancer]
|
||||
aws_cli_query = "TargetGroups[*].TargetGroupArn"
|
||||
}
|
||||
*/
|
||||
|
||||
module alb_tgs {
|
||||
source = "../../util/awscli"
|
||||
access_key = var.target-account-ak
|
||||
aws_cli_commands = "elbv2 describe-target-groups --load-balancer-arn ${var.load-balancer} --query TargetGroups[*].TargetGroupArn"
|
||||
secret_key = var.target-account-sk
|
||||
session_token = var.target-account-token
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "alb-HealthyHostCount" {
|
||||
# for_each = module.alb-targetgroups.result-set
|
||||
for_each = toset(module.alb_tgs.awscliout)
|
||||
alarm_name = "${var.settings.HealthHostCountMin.ecccode}-ALBTG_:${split(":", each.value)[5]}-HealthyHostCount"
|
||||
comparison_operator = var.settings.HealthHostCountMin.comparison_operator
|
||||
evaluation_periods = var.settings.HealthHostCountMin.evaluation_periods
|
||||
metric_name = "HealthyHostCount"
|
||||
period = var.settings.HealthHostCountMin.period
|
||||
statistic = var.settings.HealthHostCountMin.statistic
|
||||
threshold = var.settings.HealthHostCountMin.threshold
|
||||
alarm_description = "ALBTG:HealthyHostCount"
|
||||
namespace = "AWS/ApplicationELB"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.HealthHostCountMin.action]
|
||||
ok_actions = [var.settings.HealthHostCountMin.action]
|
||||
dimensions = {
|
||||
TargetGroup = split(":", each.value)[5]
|
||||
LoadBalancer = "app/${split("/", var.load-balancer)[2]}/${split("/", var.load-balancer)[3]}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
output alb-tg-count {
|
||||
# value = length(module.alb-targetgroups.result-set)
|
||||
value = length(flatten(module.alb_tgs.awscliout))
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
variable cw-alarm-prefix {}
|
||||
variable actions-enabled {}
|
||||
variable load-balancer {}
|
||||
variable settings {}
|
||||
# variable asrolearn {}
|
||||
variable target-account-ak {}
|
||||
variable target-account-sk {}
|
||||
variable target-account-token {}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "asg" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "asg"
|
||||
}
|
||||
|
||||
module "asg-monitoring" {
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = module.asg.result-set
|
||||
source = "../../modules/ManagementGovernance/Monitoring.ASG"
|
||||
default-tags = local.default-tags
|
||||
asg-name = each.value
|
||||
threshold-CPUUtilization = 90
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = var.sns-targets
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,41 @@
|
||||
data "aws_autoscaling_group" "asg" {
|
||||
name = var.asg-name
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "asg-CPUUtilization" {
|
||||
alarm_name = "${var.settings.CPUUtilization.ecccode}-ASG_${var.asg-name}-CPUUtilization"
|
||||
comparison_operator = var.settings.CPUUtilization.comparison_operator
|
||||
evaluation_periods = var.settings.CPUUtilization.evaluation_periods
|
||||
metric_name = "CPUUtilization"
|
||||
period = var.settings.CPUUtilization.period
|
||||
statistic = var.settings.CPUUtilization.statistic
|
||||
threshold = var.settings.CPUUtilization.threshold
|
||||
alarm_description = "ASG:CPUUtilization"
|
||||
namespace = "AWS/EC2"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.CPUUtilization.action]
|
||||
ok_actions = [var.settings.CPUUtilization.action]
|
||||
dimensions = {
|
||||
AutoScalingGroupName =var.asg-name
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "asg-GroupInServiceCapacity" {
|
||||
alarm_name = "${var.settings.GroupInServiceCapacity.ecccode}-ASG_${var.asg-name}-GroupInServiceCapacity"
|
||||
comparison_operator = "LessThanThreshold"
|
||||
evaluation_periods = var.settings.GroupInServiceCapacity.evaluation_periods
|
||||
metric_name = "GroupInServiceCapacity"
|
||||
period = var.settings.GroupInServiceCapacity.period
|
||||
statistic = "Minimum"
|
||||
threshold = data.aws_autoscaling_group.asg.min_size
|
||||
alarm_description = "ASG:GroupInServiceCapacity"
|
||||
namespace = "AWS/AutoScaling"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.GroupInServiceCapacity.action]
|
||||
ok_actions = [var.settings.GroupInServiceCapacity.action]
|
||||
dimensions = {
|
||||
AutoScalingGroupName = var.asg-name
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
variable cw-alarm-prefix {}
|
||||
variable actions-enabled {}
|
||||
variable asg-name {}
|
||||
variable settings {}
|
||||
variable ecccode {}
|
||||
@@ -0,0 +1,74 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "ec2-instances" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "ec2"
|
||||
}
|
||||
|
||||
module "ec2-monitoring" {
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = module.ec2-instances.result-set
|
||||
source = "../../modules/ManagementGovernance/Monitoring.EC2"
|
||||
default-tags = local.default-tags
|
||||
ec2-instance-id = each.value
|
||||
threshold-CPUUtilization = 90
|
||||
threshold-mem_free = 100000
|
||||
threshold-swap_free = 100000
|
||||
threshold-disk_free = 1 * 1000 * 1000 * 1000
|
||||
threshold-disk_inodes_free = 10000
|
||||
threshold-processes_total = 500
|
||||
threshold-LogicalDiskFreePct = 10
|
||||
threshold-MemoryCommittedPct = 90
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = var.sns-targets
|
||||
}
|
||||
```
|
||||
|
||||
## Sample cloudwatch alarm email notification
|
||||
```
|
||||
Subject: ALARM: "TestAlarmPleaseIgnore" in Asia Pacific (Hong Kong)
|
||||
|
||||
You are receiving this email because your Amazon CloudWatch Alarm "TestAlarmPleaseIgnore" in the
|
||||
Asia Pacific (Hong Kong) region has entered the ALARM state, because "Threshold Crossed: 1 out of
|
||||
the last 1 datapoints [864.0 (24/01/24 00:56:00)] was less than or equal to the threshold (900.0)
|
||||
(minimum 1 datapoint for OK -> ALARM transition)." at "Wednesday 24 January, 2024 01:01:34 UTC".
|
||||
|
||||
View this alarm in the AWS Management Console:
|
||||
https://ap-east-1.console.aws.amazon.com%2Fcloudwatch...
|
||||
|
||||
Alarm Details:
|
||||
- Name: TestAlarmPleaseIgnore
|
||||
- Description: Cloudwatch alarm for the following resource
|
||||
- Instance ID: xxx
|
||||
- Instance Name: yyy
|
||||
- Instance IP: zz.zz.zz.zz
|
||||
- State Change: OK -> ALARM
|
||||
- Reason for State Change: Threshold Crossed: 1 out of the last 1 datapoints [864.0 (24/01/24 00:56:00)] was less than or equal to the threshold (900.0) (minimum 1 datapoint for OK -> ALARM transition).
|
||||
- Timestamp: Wednesday 24 January, 2024 01:01:34 UTC
|
||||
- AWS Account: 111122223333
|
||||
- Alarm Arn: arn:aws:cloudwatch:ap-east-1:111122223333:alarm:TestAlarmPleaseIgnore
|
||||
|
||||
Threshold:
|
||||
- The alarm is in the ALARM state when the metric is LessThanOrEqualToThreshold 900.0 for at least 1 of the last 1 period(s) of 300 seconds.
|
||||
|
||||
Monitored Metric:
|
||||
- MetricNamespace: AWS/EC2
|
||||
- MetricName: CPUCreditBalance
|
||||
- Dimensions: [InstanceId = i-050d4adeafaa53cd0]
|
||||
- Period: 300 seconds
|
||||
- Statistic: Average
|
||||
- Unit: not specified
|
||||
- TreatMissingData: missing
|
||||
|
||||
|
||||
State Change Actions:
|
||||
- OK:
|
||||
- ALARM: [arn:aws:sns:ap-east-1:111122223333:CWA-SNS-Email-KenFong]
|
||||
- INSUFFICIENT_DATA:
|
||||
```
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
eval "$(jq -r '@sh "export id=\(.input) asrolearn=\(.asrolearn)"')"
|
||||
eval $(aws sts assume-role --role-arn $asrolearn --role-session-name awscli | jq -cr '"export AWS_ACCESS_KEY_ID=" + .Credentials.AccessKeyId, "export AWS_SECRET_ACCESS_KEY=" + .Credentials.SecretAccessKey, "export AWS_SESSION_TOKEN=" + .Credentials.SessionToken, "export AWS_SESSION_EXPIRATION=" + .Credentials.Expiration')
|
||||
|
||||
aws cloudwatch list-metrics --namespace CWAgent --metric-name disk_inodes_free \
|
||||
--dimensions Name=InstanceId,Value=$id Name=path,Value=/ | \
|
||||
jq '.Metrics[] | .Dimensions[] | select ((.Name=="device") or (.Name=="fstype")) | { (.Name): (.Value)}' | \
|
||||
jq -s 'add // {"device":"unknown", "fstype":"unknown"}'
|
||||
|
||||
|
||||
exit 0
|
||||
|
||||
DEVICE=$(aws cloudwatch list-metrics --namespace CWAgent --metric-name disk_inodes_free \
|
||||
--dimensions Name=InstanceId,Value=$id Name=path,Value=/ \
|
||||
--query 'Metrics[].Dimensions[?Name==`device`].Value' --output text)
|
||||
|
||||
FSTYPE=$(aws cloudwatch list-metrics --namespace CWAgent --metric-name disk_inodes_free \
|
||||
--dimensions Name=InstanceId,Value=$id Name=path,Value=/ \
|
||||
--query 'Metrics[].Dimensions[?Name==`fstype`].Value' --output text)
|
||||
|
||||
jq -n --arg device "$DEVICE" --arg fstype "$FSTYPE" '{"device":$device,"fstype":$fstype}'
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
# Get the query
|
||||
TERRAFORM_QUERY=$(jq -Mc .)
|
||||
|
||||
# Extract the query attributes
|
||||
access_key=$(echo "${TERRAFORM_QUERY}" | jq -r '.access_key')
|
||||
secret_key=$(echo "${TERRAFORM_QUERY}" | jq -r '.secret_key')
|
||||
session_token=$(echo "${TERRAFORM_QUERY}" | jq -r '.session_token')
|
||||
iid=$(echo "${TERRAFORM_QUERY}" | jq -r '.iid')
|
||||
|
||||
# eval "$(jq -r '@sh "export id=\(.input) asrolearn=\(.asrolearn)"')"
|
||||
# eval $(aws sts assume-role --role-arn $asrolearn --role-session-name awscli | jq -cr '"export AWS_ACCESS_KEY_ID=" + .Credentials.AccessKeyId, "export AWS_SECRET_ACCESS_KEY=" + .Credentials.SecretAccessKey, "export AWS_SESSION_TOKEN=" + .Credentials.SessionToken, "export AWS_SESSION_EXPIRATION=" + .Credentials.Expiration')
|
||||
|
||||
export AWS_ACCESS_KEY_ID=$access_key
|
||||
export AWS_SECRET_ACCESS_KEY=$secret_key
|
||||
export AWS_SESSION_TOKEN=$session_token
|
||||
|
||||
#aws cloudwatch list-metrics --namespace CWAgent --metric-name disk_inodes_free \
|
||||
#--dimensions Name=InstanceId,Value=$iid Name=path,Value=/ | \
|
||||
#jq '.Metrics[] | .Dimensions[] | {(.Name):(.Value)}' | jq -s 'add'
|
||||
|
||||
# when there are multiple metrics with the same name...
|
||||
aws cloudwatch list-metrics --namespace CWAgent --metric-name disk_inodes_free \
|
||||
--dimensions Name=InstanceId,Value=$iid Name=path,Value=/ --query Metrics[] | \
|
||||
jq '. | last | .Dimensions[] | {(.Name):(.Value)}' | jq -s 'add'
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
eval "$(jq -r '@sh "export id=\(.input) asrolearn=\(.asrolearn)"')"
|
||||
eval $(aws sts assume-role --role-arn $asrolearn --role-session-name awscli | jq -cr '"export AWS_ACCESS_KEY_ID=" + .Credentials.AccessKeyId, "export AWS_SECRET_ACCESS_KEY=" + .Credentials.SecretAccessKey, "export AWS_SESSION_TOKEN=" + .Credentials.SessionToken, "export AWS_SESSION_EXPIRATION=" + .Credentials.Expiration')
|
||||
|
||||
EC2OS=$(aws ec2 describe-instances --instance-ids $id | jq -r '.Reservations[].Instances[].PlatformDetails')
|
||||
|
||||
if [ $EC2OS == "Windows" ]; then
|
||||
echo '{"os": "Windows"}'
|
||||
else
|
||||
echo '{"os": "Linux"}'
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
locals {
|
||||
# alarm-message limited to 1024 characters
|
||||
alarm-message = <<EOF
|
||||
Cloudwatch alarm for the following resource
|
||||
- Instance ID: ${var.ec2-instance-id}
|
||||
- Instance Name: ${data.aws_instance.ec2-instance.tags["Name"]}
|
||||
- Instance IP: ${data.aws_instance.ec2-instance.private_ip}
|
||||
- Instance Type: ${data.aws_instance.ec2-instance.instance_type}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-StatusCheckFailed_System" {
|
||||
alarm_name = "${var.settings.StatusCheckFailed_System.ecccode}-EC2_${var.ec2-instance-id}-StatusCheckFailed_System"
|
||||
comparison_operator = var.settings.StatusCheckFailed_System.comparison_operator
|
||||
evaluation_periods = var.settings.StatusCheckFailed_System.evaluation_periods
|
||||
metric_name = "StatusCheckFailed_System"
|
||||
period = var.settings.StatusCheckFailed_System.period
|
||||
statistic = var.settings.StatusCheckFailed_System.statistic
|
||||
threshold = var.settings.StatusCheckFailed_System.threshold
|
||||
# alarm_description = "EC2:StatusCheckFailed_System"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "AWS/EC2"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.StatusCheckFailed_System.action]
|
||||
ok_actions = [var.settings.StatusCheckFailed_System.action]
|
||||
dimensions = {
|
||||
InstanceId = var.ec2-instance-id
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-StatusCheckFailed_Instance" {
|
||||
alarm_name = "${var.settings.StatusCheckFailed_Instance.ecccode}-EC2_${var.ec2-instance-id}-StatusCheckFailed_Instance"
|
||||
comparison_operator = var.settings.StatusCheckFailed_Instance.comparison_operator
|
||||
evaluation_periods = var.settings.StatusCheckFailed_Instance.evaluation_periods
|
||||
metric_name = "StatusCheckFailed_Instance"
|
||||
period = var.settings.StatusCheckFailed_Instance.period
|
||||
statistic = var.settings.StatusCheckFailed_Instance.statistic
|
||||
threshold = var.settings.StatusCheckFailed_Instance.threshold
|
||||
# alarm_description = "EC2:StatusCheckFailed_Instance"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "AWS/EC2"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.StatusCheckFailed_Instance.action]
|
||||
ok_actions = [var.settings.StatusCheckFailed_Instance.action]
|
||||
dimensions = {
|
||||
InstanceId = var.ec2-instance-id
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-CPUUtilization" {
|
||||
alarm_name = "${var.settings.CPUUtilization.ecccode}-EC2_${var.ec2-instance-id}-CPUUtilization"
|
||||
comparison_operator = var.settings.CPUUtilization.comparison_operator
|
||||
evaluation_periods = var.settings.CPUUtilization.evaluation_periods
|
||||
metric_name = "CPUUtilization"
|
||||
period = var.settings.CPUUtilization.period
|
||||
statistic = var.settings.CPUUtilization.statistic
|
||||
threshold = var.settings.CPUUtilization.threshold
|
||||
# alarm_description = "EC2:CPUUtilization"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "AWS/EC2"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.CPUUtilization.action]
|
||||
ok_actions = [var.settings.CPUUtilization.action]
|
||||
treat_missing_data = "notBreaching"
|
||||
dimensions = {
|
||||
InstanceId = var.ec2-instance-id
|
||||
}
|
||||
}
|
||||
|
||||
# cwagent metrics
|
||||
data "aws_instance" "ec2-instance" {
|
||||
instance_id = var.ec2-instance-id
|
||||
}
|
||||
|
||||
# put instance name or ip in alarm name
|
||||
locals {
|
||||
instance-ip = data.aws_instance.ec2-instance.private_ip
|
||||
instance-name = data.aws_instance.ec2-instance.tags["Name"]
|
||||
}
|
||||
|
||||
module "ec2_os" {
|
||||
source = "../../util/awscli"
|
||||
access_key = var.target-account-ak
|
||||
aws_cli_commands = "ec2 describe-instances --instance-ids ${var.ec2-instance-id} --query Reservations[].Instances[].PlatformDetails"
|
||||
secret_key = var.target-account-sk
|
||||
session_token = var.target-account-token
|
||||
}
|
||||
|
||||
# Linux specific checks
|
||||
# default cw agent uses mem_used_percent metric
|
||||
|
||||
# detect presense of cloudwatch agent
|
||||
module "detect_cloudwatch_agent" {
|
||||
source = "../../util/awscli"
|
||||
access_key = var.target-account-ak
|
||||
secret_key = var.target-account-sk
|
||||
session_token = var.target-account-token
|
||||
aws_cli_commands = "cloudwatch list-metrics --namespace CWAgent --dimensions Name=InstanceId,Value=${var.ec2-instance-id} --query Metrics[].MetricName --max-items 1"
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-mem_used_percent" {
|
||||
count = module.ec2_os.awscliout[0] != "Windows" && length(module.detect_cloudwatch_agent.awscliout) > 0 ? 1 : 0
|
||||
alarm_name = "${var.settings.mem_used_percent.ecccode}-EC2_${var.ec2-instance-id}-mem_used_percent"
|
||||
comparison_operator = var.settings.mem_used_percent.comparison_operator
|
||||
evaluation_periods = var.settings.mem_used_percent.evaluation_periods
|
||||
metric_name = "mem_used_percent"
|
||||
period = var.settings.mem_used_percent.period
|
||||
statistic = var.settings.mem_used_percent.statistic
|
||||
threshold = var.settings.mem_used_percent.threshold
|
||||
# alarm_description = "EC2:mem_used_percent"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "CWAgent"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.mem_used_percent.action]
|
||||
ok_actions = [var.settings.mem_used_percent.action]
|
||||
dimensions = {
|
||||
InstanceId = var.ec2-instance-id
|
||||
ImageId = data.aws_instance.ec2-instance.ami
|
||||
InstanceType = data.aws_instance.ec2-instance.instance_type
|
||||
}
|
||||
}
|
||||
|
||||
data "external" "cw-dimensions" {
|
||||
program = ["bash", "${path.module}/get-cwagent-dimensions.sh"]
|
||||
query = {
|
||||
iid = var.ec2-instance-id
|
||||
access_key = var.target-account-ak
|
||||
secret_key = var.target-account-sk
|
||||
session_token = var.target-account-token
|
||||
}
|
||||
}
|
||||
|
||||
/* module returns blank
|
||||
module "cw-dimensions" {
|
||||
source = "../../util/awscli"
|
||||
access_key = var.target-account-ak
|
||||
aws_cli_commands = "cloudwatch list-metrics --namespace CWAgent --metric-name disk_inodes_free --dimensions Name=InstanceId,Value=${var.ec2-instance-id} Name=path,Value=/ --query Metrics[].Dimensions[] | jq '.[] | {(.Name):(.Value)}' | jq -s 'add'"
|
||||
secret_key = var.target-account-sk
|
||||
session_token = var.target-account-token
|
||||
}
|
||||
*/
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-swap_used_percent" {
|
||||
count = module.ec2_os.awscliout[0] != "Windows" && length(module.detect_cloudwatch_agent.awscliout) > 0 ? 1 : 0
|
||||
alarm_name = "${var.settings.swap_used_percent.ecccode}-EC2_${var.ec2-instance-id}-swap_used_percent"
|
||||
comparison_operator = var.settings.swap_used_percent.comparison_operator
|
||||
evaluation_periods = var.settings.swap_used_percent.evaluation_periods
|
||||
metric_name = "swap_used_percent"
|
||||
period = var.settings.swap_used_percent.period
|
||||
statistic = var.settings.swap_used_percent.statistic
|
||||
threshold = var.settings.swap_used_percent.threshold
|
||||
# alarm_description = "EC2:swap_used_percent"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "CWAgent"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.swap_used_percent.action]
|
||||
ok_actions = [var.settings.swap_used_percent.action]
|
||||
dimensions = {
|
||||
InstanceId = var.ec2-instance-id
|
||||
ImageId = data.aws_instance.ec2-instance.ami
|
||||
InstanceType = data.aws_instance.ec2-instance.instance_type
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-disk_used_percent_warn" {
|
||||
count = module.ec2_os.awscliout[0] != "Windows" && data.external.cw-dimensions.result != null ? 1 : 0
|
||||
alarm_name = "${var.settings.disk_used_percent_warn.ecccode}-EC2_${var.ec2-instance-id}-disk_used_percent"
|
||||
comparison_operator = var.settings.disk_used_percent_warn.comparison_operator
|
||||
evaluation_periods = var.settings.disk_used_percent_warn.evaluation_periods
|
||||
metric_name = "disk_used_percent"
|
||||
period = var.settings.disk_used_percent_warn.period
|
||||
statistic = var.settings.disk_used_percent_warn.statistic
|
||||
threshold = var.settings.disk_used_percent_warn.threshold
|
||||
# alarm_description = "EC2:disk_used_percent"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "CWAgent"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.disk_used_percent_warn.action]
|
||||
ok_actions = [var.settings.disk_used_percent_warn.action]
|
||||
dimensions = data.external.cw-dimensions.result
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-disk_used_percent_crit" {
|
||||
count = module.ec2_os.awscliout[0] != "Windows" && data.external.cw-dimensions.result != null ? 1 : 0
|
||||
alarm_name = "${var.settings.disk_used_percent_crit.ecccode}-EC2_${var.ec2-instance-id}-disk_used_percent"
|
||||
comparison_operator = var.settings.disk_used_percent_crit.comparison_operator
|
||||
evaluation_periods = var.settings.disk_used_percent_crit.evaluation_periods
|
||||
metric_name = "disk_used_percent"
|
||||
period = var.settings.disk_used_percent_crit.period
|
||||
statistic = var.settings.disk_used_percent_crit.statistic
|
||||
threshold = var.settings.disk_used_percent_crit.threshold
|
||||
# alarm_description = "EC2:disk_used_percent"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "CWAgent"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.disk_used_percent_crit.action]
|
||||
ok_actions = [var.settings.disk_used_percent_crit.action]
|
||||
dimensions = data.external.cw-dimensions.result
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-disk_inodes_free" {
|
||||
count = module.ec2_os.awscliout[0] != "Windows" && data.external.cw-dimensions.result != null ? 1 : 0
|
||||
alarm_name = "${var.settings.disk_inodes_free.ecccode}-EC2_${var.ec2-instance-id}-disk_inodes_free"
|
||||
comparison_operator = var.settings.disk_inodes_free.comparison_operator
|
||||
evaluation_periods = var.settings.disk_inodes_free.evaluation_periods
|
||||
metric_name = "disk_inodes_free"
|
||||
period = var.settings.disk_inodes_free.period
|
||||
statistic = var.settings.disk_inodes_free.statistic
|
||||
threshold = var.settings.disk_inodes_free.threshold
|
||||
# alarm_description = "EC2:disk_inodes_free"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "CWAgent"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.disk_inodes_free.action]
|
||||
ok_actions = [var.settings.disk_inodes_free.action]
|
||||
dimensions = data.external.cw-dimensions.result
|
||||
}
|
||||
|
||||
# process metric not published by default cw agent config
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-processes_total" {
|
||||
count = module.ec2_os.awscliout[0] != "Windows" && length(module.detect_cloudwatch_agent.awscliout) > 0 ? 1 : 0
|
||||
alarm_name = "${var.settings.processes_total.ecccode}-EC2_${var.ec2-instance-id}-processes_total"
|
||||
comparison_operator = var.settings.processes_total.comparison_operator
|
||||
evaluation_periods = var.settings.processes_total.evaluation_periods
|
||||
metric_name = "processes_total"
|
||||
period = var.settings.processes_total.period
|
||||
statistic = var.settings.processes_total.statistic
|
||||
threshold = var.settings.processes_total.threshold
|
||||
# alarm_description = "EC2:processes_total"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "CWAgent"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.processes_total.action]
|
||||
ok_actions = [var.settings.processes_total.action]
|
||||
dimensions = {
|
||||
InstanceId = var.ec2-instance-id
|
||||
ImageId = data.aws_instance.ec2-instance.ami
|
||||
InstanceType = data.aws_instance.ec2-instance.instance_type
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-net_err" {
|
||||
count = module.ec2_os.awscliout[0] != "Windows" && length(module.detect_cloudwatch_agent.awscliout) > 0 ? 1 : 0
|
||||
alarm_name = "${var.settings.net_err_in.ecccode}-EC2_${var.ec2-instance-id}-net_err"
|
||||
comparison_operator = "GreaterThanThreshold"
|
||||
evaluation_periods = var.settings.net_err_in.evaluation_periods
|
||||
threshold = 0
|
||||
# alarm_description = "EC2:net_err_in or EC2:net_err_out exceeds threshold"
|
||||
alarm_description = local.alarm-message
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = false
|
||||
alarm_actions = [var.settings.net_err_in.action]
|
||||
ok_actions = [var.settings.net_err_in.action]
|
||||
treat_missing_data = "notBreaching"
|
||||
|
||||
metric_query {
|
||||
id = "e1"
|
||||
expression = "IF(m1 > ${var.settings.net_err_in.threshold} OR m2 > ${var.settings.net_err_out.threshold}, 1, 0)"
|
||||
label = "net_err_exceeds_threshold"
|
||||
return_data = "true"
|
||||
}
|
||||
|
||||
metric_query {
|
||||
id = "m1"
|
||||
metric {
|
||||
metric_name = "net_err_in"
|
||||
namespace = "CWAgent"
|
||||
period = var.settings.net_err_in.period
|
||||
stat = var.settings.net_err_in.statistic
|
||||
dimensions = {
|
||||
InstanceId = var.ec2-instance-id
|
||||
ImageId = data.aws_instance.ec2-instance.ami
|
||||
InstanceType = data.aws_instance.ec2-instance.instance_type
|
||||
interface = "eth0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
metric_query {
|
||||
id = "m2"
|
||||
metric {
|
||||
metric_name = "net_err_out"
|
||||
namespace = "CWAgent"
|
||||
period = var.settings.net_err_out.period
|
||||
stat = var.settings.net_err_out.statistic
|
||||
dimensions = {
|
||||
InstanceId = var.ec2-instance-id
|
||||
ImageId = data.aws_instance.ec2-instance.ami
|
||||
InstanceType = data.aws_instance.ec2-instance.instance_type
|
||||
interface = "eth0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-NetworkIn" {
|
||||
count = try(var.settings.NetworkIn.monitor, false) ? 1 : 0
|
||||
alarm_name = "${var.settings.NetworkIn.ecccode}-EC2_${var.ec2-instance-id}-NetworkIn"
|
||||
comparison_operator = var.settings.NetworkIn.comparison_operator
|
||||
evaluation_periods = var.settings.NetworkIn.evaluation_periods
|
||||
metric_name = "NetworkIn"
|
||||
period = var.settings.NetworkIn.period
|
||||
statistic = var.settings.NetworkIn.statistic
|
||||
threshold = var.settings.NetworkIn.threshold
|
||||
# alarm_description = "EC2:NetworkIn"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "AWS/EC2"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.NetworkIn.action]
|
||||
ok_actions = [var.settings.NetworkIn.action]
|
||||
dimensions = {
|
||||
InstanceId = var.ec2-instance-id
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-NetworkOut" {
|
||||
count = try(var.settings.NetworkIn.monitor, false) ? 1 : 0
|
||||
alarm_name = "${var.settings.NetworkOut.ecccode}-EC2_${var.ec2-instance-id}-NetworkOut"
|
||||
comparison_operator = var.settings.NetworkOut.comparison_operator
|
||||
evaluation_periods = var.settings.NetworkOut.evaluation_periods
|
||||
metric_name = "NetworkOut"
|
||||
period = var.settings.NetworkOut.period
|
||||
statistic = var.settings.NetworkOut.statistic
|
||||
threshold = var.settings.NetworkOut.threshold
|
||||
# alarm_description = "EC2:NetworkOut"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "AWS/EC2"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.NetworkOut.action]
|
||||
ok_actions = [var.settings.NetworkOut.action]
|
||||
dimensions = {
|
||||
InstanceId = var.ec2-instance-id
|
||||
}
|
||||
}
|
||||
|
||||
# Windows specific checks
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-MemoryCommittedPct" {
|
||||
count = module.ec2_os.awscliout[0] == "Windows" && length(module.detect_cloudwatch_agent.awscliout) > 0 ? 1 : 0
|
||||
alarm_name = "${var.settings.MemoryCommittedPct.ecccode}-EC2_${var.ec2-instance-id}-MemoryCommittedPct"
|
||||
comparison_operator = var.settings.MemoryCommittedPct.comparison_operator
|
||||
evaluation_periods = var.settings.MemoryCommittedPct.evaluation_periods
|
||||
metric_name = "Memory % Committed Bytes In Use"
|
||||
period = var.settings.MemoryCommittedPct.period
|
||||
statistic = var.settings.MemoryCommittedPct.statistic
|
||||
threshold = var.settings.MemoryCommittedPct.threshold
|
||||
# alarm_description = "EC2:MemoryCommittedBytes"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "CWAgent"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.MemoryCommittedPct.action]
|
||||
ok_actions = [var.settings.MemoryCommittedPct.action]
|
||||
dimensions = {
|
||||
objectname = "Memory"
|
||||
InstanceId = var.ec2-instance-id
|
||||
ImageId = data.aws_instance.ec2-instance.ami
|
||||
InstanceType = data.aws_instance.ec2-instance.instance_type
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ec2-LogicalDiskFreePct" {
|
||||
count = module.ec2_os.awscliout[0] == "Windows" && length(module.detect_cloudwatch_agent.awscliout) > 0 ? 1 : 0
|
||||
alarm_name = "${var.settings.LogicalDiskFreePct.ecccode}-EC2_${var.ec2-instance-id}-LogicalDiskFreePct"
|
||||
comparison_operator = var.settings.LogicalDiskFreePct.comparison_operator
|
||||
evaluation_periods = var.settings.LogicalDiskFreePct.evaluation_periods
|
||||
metric_name = "LogicalDisk % Free Space"
|
||||
period = var.settings.LogicalDiskFreePct.period
|
||||
statistic = var.settings.LogicalDiskFreePct.statistic
|
||||
threshold = var.settings.LogicalDiskFreePct.threshold
|
||||
# alarm_description = "EC2:OsDiskFreePct"
|
||||
alarm_description = local.alarm-message
|
||||
namespace = "CWAgent"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.LogicalDiskFreePct.action]
|
||||
ok_actions = [var.settings.LogicalDiskFreePct.action]
|
||||
dimensions = {
|
||||
instance = "C:"
|
||||
objectname = "LogicalDisk"
|
||||
InstanceId = var.ec2-instance-id
|
||||
ImageId = data.aws_instance.ec2-instance.ami
|
||||
InstanceType = data.aws_instance.ec2-instance.instance_type
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
variable "cw-alarm-prefix" {}
|
||||
variable "actions-enabled" {}
|
||||
variable "ec2-instance-id" {}
|
||||
variable "settings" {}
|
||||
# variable asrolearn {}
|
||||
variable target-account-ak {}
|
||||
variable target-account-sk {}
|
||||
variable target-account-token {}
|
||||
@@ -0,0 +1,27 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
Unlike other monitoring modules which discovers resources details automatically, EKS pod name need to be supplied to this module.
|
||||
AWS cli does not provide pod information.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
data "aws_eks_clusters" "eks-clusters" {}
|
||||
|
||||
module "eks-monitoring" {
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = data.aws_eks_clusters.eks-clusters.names
|
||||
source = "../../modules/ManagementGovernance/Monitoring.EKS"
|
||||
default-tags = local.default-tags
|
||||
cluster-name = each.value
|
||||
eks-namespace = "default"
|
||||
pod-names = ["depl-nginx", "depl-alpine"]
|
||||
threshold-pod_cpu_utilization = 85
|
||||
threshold-pod_memory_utilization = 85
|
||||
threshold-pod_number_of_container_restarts = 5
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = local.sns-targets
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
// The following checks requires container insights
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "eks-pod_cpu_utilization" {
|
||||
for_each = toset(var.pod-names)
|
||||
alarm_name = "${each.value["ecccode"]}:${var.cw-alarm-prefix}:EKS:${var.cluster-name}:${each.value}:${var.settings.alarm1.metric}"
|
||||
comparison_operator = var.settings.alarm1.comparison_operator
|
||||
evaluation_periods = var.settings.alarm1.evaluation_periods
|
||||
metric_name = var.settings.alarm1.metric
|
||||
period = var.settings.alarm1.period
|
||||
statistic = var.settings.alarm1.statistic
|
||||
threshold = var.settings.alarm1.threshold
|
||||
alarm_description = "EKS:${var.settings.alarm1.metric}"
|
||||
namespace = "ContainerInsights"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.alarm1.action]
|
||||
ok_actions = [var.settings.alarm1.action]
|
||||
dimensions = {
|
||||
"PodName" = each.value
|
||||
"ClusterName" = var.cluster-name
|
||||
"Namespace" = var.eks-namespace
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "eks-pod_memory_utilization" {
|
||||
for_each = toset(var.pod-names)
|
||||
|
||||
alarm_name = "${each.value["ecccode"]}:${var.cw-alarm-prefix}:EKS:${var.cluster-name}:${each.value}:${var.settings.alarm2.metric}"
|
||||
comparison_operator = "GreaterThanThreshold"
|
||||
evaluation_periods = "3"
|
||||
metric_name = var.settings.alarm2.metric
|
||||
period = var.settings.alarm2.period
|
||||
statistic = var.settings.alarm2.statistic
|
||||
threshold = var.settings.alarm2.threshold
|
||||
alarm_description = "EKS:${var.settings.alarm2.metric}"
|
||||
namespace = "ContainerInsights"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.alarm2.action]
|
||||
ok_actions = [var.settings.alarm2.action]
|
||||
dimensions = {
|
||||
"PodName" = each.value
|
||||
"ClusterName" = var.cluster-name
|
||||
"Namespace" = var.eks-namespace
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "eks-pod_number_of_container_restarts" {
|
||||
for_each = toset(var.pod-names)
|
||||
|
||||
alarm_name = "${each.value["ecccode"]}:${var.cw-alarm-prefix}:EKS:${var.cluster-name}:${each.value}:${var.settings.alarm3.metric}"
|
||||
comparison_operator = "GreaterThanThreshold"
|
||||
evaluation_periods = "3"
|
||||
metric_name = var.settings.alarm3.metric
|
||||
period = var.settings.alarm3.period
|
||||
statistic = var.settings.alarm3.statistic
|
||||
threshold = var.settings.alarm3.threshold
|
||||
alarm_description = "EKS:${var.settings.alarm3.metric}"
|
||||
namespace = "ContainerInsights"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.alarm3.action]
|
||||
ok_actions = [var.settings.alarm3.action]
|
||||
dimensions = {
|
||||
"PodName" = each.value
|
||||
"ClusterName" = var.cluster-name
|
||||
"Namespace" = var.eks-namespace
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
variable cw-alarm-prefix {}
|
||||
variable actions-enabled {}
|
||||
variable cluster-name {}
|
||||
variable eks-namespace {}
|
||||
variable pod-names {
|
||||
type = list
|
||||
}
|
||||
variable settings {}
|
||||
@@ -0,0 +1,25 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "emr-clusters" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "emr"
|
||||
}
|
||||
|
||||
module "emr-monitoring" {
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = module.emr-clusters.result-set
|
||||
source = "../../modules/ManagementGovernance/Monitoring.EMR"
|
||||
default-tags = local.default-tags
|
||||
job-flow-id = split("/", each.value)[1]
|
||||
threshold-AppsPending = 2
|
||||
threshold-CapacityRemainingGB = 100
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = var.sns-targets
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,19 @@
|
||||
resource "aws_cloudwatch_metric_alarm" "emr-alarms" {
|
||||
for_each = var.settings
|
||||
alarm_name = "${each.value["ecccode"]}-EMR_${var.job-flow-id}-${each.value["metric"]}"
|
||||
comparison_operator = each.value["comparison_operator"]
|
||||
evaluation_periods = each.value["evaluation_periods"]
|
||||
metric_name = each.value["metric"]
|
||||
period = each.value["period"]
|
||||
statistic = each.value["statistic"]
|
||||
threshold = each.value["threshold"]
|
||||
alarm_description = "EMR:${each.value["metric"]}"
|
||||
namespace = "AWS/ElasticMapReduce"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [each.value["action"]]
|
||||
ok_actions = [each.value["action"]]
|
||||
dimensions = {
|
||||
JobFlowId = var.job-flow-id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
variable cw-alarm-prefix {}
|
||||
variable actions-enabled {}
|
||||
variable job-flow-id {}
|
||||
variable settings {}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
@@ -0,0 +1,46 @@
|
||||
resource "aws_cloudwatch_event_rule" "EventRule" {
|
||||
name = "${var.cw-alarm-prefix}-health-events"
|
||||
description = "A CloudWatch Event Rule that triggers on changes in the status of AWS Personal Health Dashboard (AWS Health) and forwards the events to an SNS topic."
|
||||
state = var.actions-enabled
|
||||
event_pattern = <<PATTERN
|
||||
{
|
||||
"detail": {
|
||||
"service": ["DIRECTCONNECT", "VPN", "LAMBDA", "EC2", "RDS"]
|
||||
},
|
||||
"detail-type": [
|
||||
"AWS Health Event"
|
||||
],
|
||||
"source": [
|
||||
"aws.health"
|
||||
]
|
||||
}
|
||||
PATTERN
|
||||
lifecycle {
|
||||
ignore_changes = [tags["LastModified"]]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_target" "TargetForEventRule" {
|
||||
rule = aws_cloudwatch_event_rule.EventRule.name
|
||||
# target_id = "health-event-notification-sns"
|
||||
arn = var.settings.healthEvents.action
|
||||
input_transformer {
|
||||
input_paths = {
|
||||
"account" : "$.account",
|
||||
"endTime" : "$.detail.endTime",
|
||||
"message" : "$.detail.eventDescription[0].latestDescription",
|
||||
"resources" : "$.resources",
|
||||
"service" : "$.detail.service",
|
||||
"startTime" : "$.detail.startTime"
|
||||
}
|
||||
input_template = <<EOF
|
||||
"A maintenance has been scheduled for <service> on AWS account <account>."
|
||||
|
||||
"Resources: <resources>"
|
||||
"Start time: <startTime>"
|
||||
"End time: <endTime>"
|
||||
|
||||
"Detail: <message>"
|
||||
EOF
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
variable cw-alarm-prefix {}
|
||||
variable actions-enabled {}
|
||||
variable settings {}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "kafka-clusters" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "kafka"
|
||||
}
|
||||
|
||||
module "kafka-monitoring" {
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = module.kafka-clusters.result-set
|
||||
source = "../../modules/ManagementGovernance/Monitoring.Kafka"
|
||||
default-tags = local.default-tags
|
||||
cluster-name = each.value
|
||||
threshold-ZooKeeperRequestLatencyMsMean = 30
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = var.sns-targets
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,116 @@
|
||||
resource "aws_cloudwatch_metric_alarm" "Kafka-ZooKeeperRequestLatencyMsMean" {
|
||||
alarm_name = "${var.settings.ZooKeeperRequestLatencyMsMean.ecccode}-Kafka_${var.cluster-name}-ZooKeeperRequestLatencyMsMean"
|
||||
comparison_operator = var.settings.ZooKeeperRequestLatencyMsMean.comparison_operator
|
||||
evaluation_periods = var.settings.ZooKeeperRequestLatencyMsMean.evaluation_periods
|
||||
metric_name = "ZooKeeperRequestLatencyMsMean"
|
||||
period = var.settings.ZooKeeperRequestLatencyMsMean.period
|
||||
statistic = var.settings.ZooKeeperRequestLatencyMsMean.statistic
|
||||
threshold = var.settings.ZooKeeperRequestLatencyMsMean.threshold
|
||||
alarm_description = "Kafka:ZooKeeperRequestLatencyMsMean"
|
||||
namespace = "AWS/Kafka"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.ZooKeeperRequestLatencyMsMean.action]
|
||||
ok_actions = [var.settings.ZooKeeperRequestLatencyMsMean.action]
|
||||
dimensions = {
|
||||
"Cluster Name" = var.cluster-name
|
||||
}
|
||||
}
|
||||
|
||||
data "aws_msk_cluster" "msk-cluster" {
|
||||
cluster_name = var.cluster-name
|
||||
}
|
||||
|
||||
data "aws_msk_broker_nodes" "msk-broker" {
|
||||
cluster_arn = data.aws_msk_cluster.msk-cluster.arn
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "Kafka-CpuUserSystem" {
|
||||
for_each = toset([for i in data.aws_msk_broker_nodes.msk-broker.node_info_list[*].broker_id : tostring(i)])
|
||||
alarm_name = "${var.settings.CpuUserSystem.ecccode}-Kafka_${var.cluster-name}-${each.value}-CpuUsage"
|
||||
comparison_operator = var.settings.CpuUserSystem.comparison_operator
|
||||
evaluation_periods = var.settings.CpuUserSystem.evaluation_periods
|
||||
threshold = var.settings.CpuUserSystem.threshold
|
||||
alarm_description = "Kafka:ZooKeeperRequestLatencyMsMean"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.CpuUserSystem.action]
|
||||
ok_actions = [var.settings.CpuUserSystem.action]
|
||||
metric_query {
|
||||
id = "m1"
|
||||
metric {
|
||||
metric_name = "CpuUser"
|
||||
namespace = "AWS/Kafka"
|
||||
period = var.settings.CpuUserSystem.period
|
||||
stat = var.settings.CpuUserSystem.statistic
|
||||
dimensions = {
|
||||
"Cluster Name" = var.cluster-name
|
||||
"Broker ID" = each.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
metric_query {
|
||||
id = "m2"
|
||||
metric {
|
||||
metric_name = "CpuSystem"
|
||||
namespace = "AWS/Kafka"
|
||||
period = var.settings.CpuUserSystem.period
|
||||
stat = var.settings.CpuUserSystem.statistic
|
||||
dimensions = {
|
||||
"Cluster Name" = var.cluster-name
|
||||
"Broker ID" = each.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
metric_query {
|
||||
id = "e1"
|
||||
expression = "m1 + m2"
|
||||
label = "CpuUserSystem"
|
||||
return_data = "true"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "Kafka-KafkaDataLogsDiskUsed" {
|
||||
for_each = toset([for i in data.aws_msk_broker_nodes.msk-broker.node_info_list[*].broker_id : tostring(i)])
|
||||
alarm_name = "${var.settings.KafkaDataLogsDiskUsed.ecccode}-Kafka_${var.cluster-name}-${each.value}-KafkaDataLogsDiskUsed"
|
||||
comparison_operator = var.settings.KafkaDataLogsDiskUsed.comparison_operator
|
||||
evaluation_periods = var.settings.KafkaDataLogsDiskUsed.evaluation_periods
|
||||
metric_name = "KafkaDataLogsDiskUsed"
|
||||
period = var.settings.KafkaDataLogsDiskUsed.period
|
||||
statistic = var.settings.KafkaDataLogsDiskUsed.statistic
|
||||
threshold = var.settings.KafkaDataLogsDiskUsed.threshold
|
||||
alarm_description = "Kafka:KafkaDataLogsDiskUsed"
|
||||
namespace = "AWS/Kafka"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.KafkaDataLogsDiskUsed.action]
|
||||
ok_actions = [var.settings.KafkaDataLogsDiskUsed.action]
|
||||
dimensions = {
|
||||
"Cluster Name" = var.cluster-name
|
||||
"Broker ID" = each.value
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "Kafka-HeapMemoryAfterGC" {
|
||||
for_each = toset([for i in data.aws_msk_broker_nodes.msk-broker.node_info_list[*].broker_id : tostring(i)])
|
||||
alarm_name = "${var.settings.HeapMemoryAfterGC.ecccode}-Kafka_${var.cluster-name}-${each.value}-HeapMemoryAfterGC"
|
||||
comparison_operator = var.settings.HeapMemoryAfterGC.comparison_operator
|
||||
evaluation_periods = var.settings.HeapMemoryAfterGC.evaluation_periods
|
||||
metric_name = "HeapMemoryAfterGC"
|
||||
period = var.settings.HeapMemoryAfterGC.period
|
||||
statistic = var.settings.HeapMemoryAfterGC.statistic
|
||||
threshold = var.settings.HeapMemoryAfterGC.threshold
|
||||
alarm_description = "Kafka:HeapMemoryAfterGC"
|
||||
namespace = "AWS/Kafka"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.HeapMemoryAfterGC.action]
|
||||
ok_actions = [var.settings.HeapMemoryAfterGC.action]
|
||||
dimensions = {
|
||||
"Cluster Name" = var.cluster-name
|
||||
"Broker ID" = each.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
variable cw-alarm-prefix {}
|
||||
variable actions-enabled {}
|
||||
variable cluster-name {}
|
||||
variable settings {}
|
||||
@@ -0,0 +1,26 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "ngw" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "ngw"
|
||||
}
|
||||
|
||||
module "ngw-monitoring" {
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = module.ngw.result-set
|
||||
source = "../../modules/ManagementGovernance/Monitoring.NGW"
|
||||
default-tags = local.default-tags
|
||||
job-flow-id = split("/", each.value)[1]
|
||||
threshold-ErrorPortAllocation = 2
|
||||
threshold-ConnectionEstablishedCount = 1000
|
||||
threshold-PacketsDropCount = 10
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = var.sns-targets
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,19 @@
|
||||
resource "aws_cloudwatch_metric_alarm" "ngw-alarms" {
|
||||
for_each = var.settings
|
||||
alarm_name = "${each.value["ecccode"]}-NGW_${var.res-id}-${each.value["metric"]}"
|
||||
comparison_operator = each.value["comparison_operator"]
|
||||
evaluation_periods = each.value["evaluation_periods"]
|
||||
metric_name = each.value["metric"]
|
||||
period = each.value["period"]
|
||||
statistic = each.value["statistic"]
|
||||
threshold = each.value["threshold"]
|
||||
alarm_description = "NGW:${each.value["metric"]}"
|
||||
namespace = "AWS/NATGateway"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [each.value["action"]]
|
||||
ok_actions = [each.value["action"]]
|
||||
dimensions = {
|
||||
NatGatewayId = var.res-id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
variable cw-alarm-prefix {}
|
||||
variable actions-enabled {}
|
||||
variable res-id {}
|
||||
variable settings {}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "nlb-arns" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "nlb"
|
||||
}
|
||||
|
||||
module "nlb-monitoring" {
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = module.nlb-arns.result-set
|
||||
source = "../../modules/ManagementGovernance/Monitoring.NLB"
|
||||
default-tags = local.default-tags
|
||||
load-balancer = each.value
|
||||
threshold-HealthHostCountMin = 1
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = var.sns-targets
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
data "external" "nlb-targetgroups" {
|
||||
program = ["bash", "${path.module}/list-nlb-targetgroups.sh"]
|
||||
query = {
|
||||
parameter = var.load-balancer
|
||||
}
|
||||
}
|
||||
*/
|
||||
locals {
|
||||
nlb-name = "net/${split("/", var.load-balancer)[2]}/${split("/", var.load-balancer)[3]}"
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "nlb-TCP_Target_Reset_Count" {
|
||||
alarm_name = "${var.settings.TCP_Target_Reset_Count.ecccode}-NLB_${local.nlb-name}-TCP_Target_Reset_Count"
|
||||
comparison_operator = var.settings.TCP_Target_Reset_Count.comparison_operator
|
||||
evaluation_periods = var.settings.TCP_Target_Reset_Count.evaluation_periods
|
||||
metric_name = "TCP_Target_Reset_Count"
|
||||
period = var.settings.TCP_Target_Reset_Count.period
|
||||
statistic = var.settings.TCP_Target_Reset_Count.statistic
|
||||
threshold = var.settings.TCP_Target_Reset_Count.threshold
|
||||
alarm_description = "NLB:TCP_Target_Reset_Count"
|
||||
namespace = "AWS/NetworkELB"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.TCP_Target_Reset_Count.action]
|
||||
ok_actions = [var.settings.TCP_Target_Reset_Count.action]
|
||||
dimensions = {
|
||||
LoadBalancer = local.nlb-name
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
module "nlb-targetgroups" {
|
||||
source = "../../util/resource-list"
|
||||
resource-type = "nlb-targetgroups"
|
||||
query-input = var.load-balancer
|
||||
asrolearn = var.asrolearn
|
||||
}
|
||||
*/
|
||||
|
||||
// causes Rate exceeded error, maybe because of adaptive AWS_RETRY_MODE?
|
||||
|
||||
/*
|
||||
module "nlb_tgs" {
|
||||
assume_role_arn = var.asrolearn
|
||||
role_session_name = "terraform-resource-list"
|
||||
source = "../../util/terraform-aws-cli"
|
||||
aws_cli_commands = ["elbv2", "describe-target-groups", "--load-balancer-arn", var.load-balancer]
|
||||
aws_cli_query = "TargetGroups[*].TargetGroupArn"
|
||||
}
|
||||
*/
|
||||
|
||||
module nlb_tgs {
|
||||
source = "../../util/awscli"
|
||||
access_key = var.target-account-ak
|
||||
aws_cli_commands = "elbv2 describe-target-groups --load-balancer-arn ${var.load-balancer} --query TargetGroups[*].TargetGroupArn"
|
||||
secret_key = var.target-account-sk
|
||||
session_token = var.target-account-token
|
||||
}
|
||||
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "nlb-HealthyHostCount" {
|
||||
# for_each = module.nlb-targetgroups.result-set
|
||||
for_each = toset(module.nlb_tgs.awscliout)
|
||||
alarm_name = "${var.settings.HealthHostCountMin.ecccode}-NLBTG_${split(":", each.value)[5]}-HealthyHostCount"
|
||||
comparison_operator = var.settings.HealthHostCountMin.comparison_operator
|
||||
evaluation_periods = var.settings.HealthHostCountMin.evaluation_periods
|
||||
metric_name = "HealthyHostCount"
|
||||
period = var.settings.HealthHostCountMin.period
|
||||
statistic = var.settings.HealthHostCountMin.statistic
|
||||
threshold = var.settings.HealthHostCountMin.threshold
|
||||
alarm_description = "NLBTG:HealthyHostCount"
|
||||
namespace = "AWS/NetworkELB"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.HealthHostCountMin.action]
|
||||
ok_actions = [var.settings.HealthHostCountMin.action]
|
||||
dimensions = {
|
||||
TargetGroup = split(":", each.value)[5]
|
||||
LoadBalancer = "net/${split("/", var.load-balancer)[2]}/${split("/", var.load-balancer)[3]}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "nlb-UnHealthyHostCount" {
|
||||
# for_each = module.nlb-targetgroups.result-set
|
||||
for_each = toset(module.nlb_tgs.awscliout)
|
||||
alarm_name = "${var.settings.UnHealthyHostCount.ecccode}-NLBTG_${split(":", each.value)[5]}-UnHealthyHostCount"
|
||||
comparison_operator = var.settings.UnHealthyHostCount.comparison_operator
|
||||
evaluation_periods = var.settings.UnHealthyHostCount.evaluation_periods
|
||||
metric_name = "UnHealthyHostCount"
|
||||
period = var.settings.UnHealthyHostCount.period
|
||||
statistic = var.settings.UnHealthyHostCount.statistic
|
||||
threshold = var.settings.UnHealthyHostCount.threshold
|
||||
alarm_description = "NLBTG:UnHealthyHostCount"
|
||||
namespace = "AWS/NetworkELB"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [var.settings.UnHealthyHostCount.action]
|
||||
ok_actions = [var.settings.UnHealthyHostCount.action]
|
||||
dimensions = {
|
||||
TargetGroup = split(":", each.value)[5]
|
||||
LoadBalancer = "net/${split("/", var.load-balancer)[2]}/${split("/", var.load-balancer)[3]}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
output nlb-tg-count {
|
||||
# value = length(module.nlb-targetgroups.result-set)
|
||||
value = length(flatten(module.nlb_tgs.awscliout))
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
variable cw-alarm-prefix {}
|
||||
variable actions-enabled {}
|
||||
variable load-balancer {}
|
||||
variable settings {}
|
||||
# variable asrolearn {}
|
||||
variable target-account-ak {}
|
||||
variable target-account-sk {}
|
||||
variable target-account-token {}
|
||||
@@ -0,0 +1,27 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "es-domains" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "opensearch"
|
||||
}
|
||||
|
||||
module "es-monitoring" {
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = module.es-domains.result-set
|
||||
source = "../../modules/ManagementGovernance/Monitoring.OpenSearch"
|
||||
default-tags = local.default-tags
|
||||
domain-name = each.value
|
||||
threshold-CPUUtilization = 90
|
||||
threshold-IndexingLatency = 3
|
||||
threshold-SearchLatency = 3
|
||||
# threshold-KibanaHealthyNodes = 1
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = var.sns-targets
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,22 @@
|
||||
data "aws_caller_identity" "this" {}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "ES-alarms" {
|
||||
for_each = var.settings
|
||||
alarm_name = "${each.value["ecccode"]}-ES_${var.domain-name}-${each.value["metric"]}"
|
||||
comparison_operator = each.value["comparison_operator"]
|
||||
evaluation_periods = each.value["evaluation_periods"]
|
||||
metric_name = each.value["metric"]
|
||||
period = each.value["period"]
|
||||
statistic = each.value["statistic"]
|
||||
threshold = each.value["threshold"]
|
||||
alarm_description = "ES:${each.value["metric"]}"
|
||||
namespace = "AWS/ES"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [each.value["action"]]
|
||||
ok_actions = [each.value["action"]]
|
||||
dimensions = {
|
||||
DomainName = var.domain-name
|
||||
ClientId = data.aws_caller_identity.this.id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
variable "cw-alarm-prefix" {}
|
||||
variable "actions-enabled" {}
|
||||
variable "domain-name" {}
|
||||
variable "settings" {}
|
||||
@@ -0,0 +1,31 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
AWS provider 4.47.0 or above is needed for datasource aws_db_instances (https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md)
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "rds-instances" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "rds"
|
||||
}
|
||||
|
||||
module "rds-monitoring" {
|
||||
# for_each = toset(var.rds-instance-ids)
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = module.rds-instances.result-set
|
||||
source = "../../modules/ManagementGovernance/Monitoring.RDS"
|
||||
default-tags = local.default-tags
|
||||
rds-instance-name = each.value
|
||||
threshold-CpuUtilization = 90
|
||||
threshold-FreeableMemory = 512 * 1024 * 1024
|
||||
threshold-FreeStorageSpace = 5 * 1024 * 1024 * 1024
|
||||
threshold-DiskQueueDepth = 30
|
||||
threshold-ReadLatency = 0.03
|
||||
threshold-WriteLatency = 0.03
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = var.sns-targets
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,19 @@
|
||||
resource "aws_cloudwatch_metric_alarm" "rds-alarms" {
|
||||
for_each = var.settings
|
||||
alarm_name = "${each.value["ecccode"]}-RDS_${var.rds-instance-name}-${each.value["metric"]}"
|
||||
comparison_operator = each.value["comparison_operator"]
|
||||
evaluation_periods = each.value["evaluation_periods"]
|
||||
metric_name = each.value["metric"]
|
||||
period = each.value["period"]
|
||||
statistic = each.value["statistic"]
|
||||
threshold = each.value["threshold"]
|
||||
alarm_description = "RDS:${each.value["metric"]}"
|
||||
namespace = "AWS/RDS"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [each.value["action"]]
|
||||
ok_actions = [each.value["action"]]
|
||||
dimensions = {
|
||||
DBInstanceIdentifier = var.rds-instance-name
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.47.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
variable cw-alarm-prefix {}
|
||||
variable actions-enabled {}
|
||||
variable rds-instance-name {}
|
||||
variable settings {}
|
||||
@@ -0,0 +1,26 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "redis-instances" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "redis"
|
||||
}
|
||||
|
||||
module "redis-monitoring" {
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = module.redis-instances.result-set
|
||||
source = "../../modules/ManagementGovernance/Monitoring.Redis"
|
||||
default-tags = local.default-tags
|
||||
redis-cluster-id = each.value
|
||||
threshold-EngineCPUUtilization = 90
|
||||
threshold-DatabaseMemoryUsagePercentage = 90
|
||||
threshold-CacheHitRate = 3
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = var.sns-targets
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,21 @@
|
||||
resource "aws_cloudwatch_metric_alarm" "redis-alarms" {
|
||||
for_each = var.settings
|
||||
alarm_name = "${each.value["ecccode"]}-Redis_${var.redis-cluster-id}-${each.value["metric"]}"
|
||||
comparison_operator = each.value["comparison_operator"]
|
||||
evaluation_periods = each.value["evaluation_periods"]
|
||||
metric_name = each.value["metric"]
|
||||
period = each.value["period"]
|
||||
statistic = each.value["statistic"]
|
||||
threshold = each.value["threshold"]
|
||||
alarm_description = "ElastiCache:${each.value["metric"]}"
|
||||
namespace = "AWS/ElastiCache"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [each.value["action"]]
|
||||
ok_actions = [each.value["action"]]
|
||||
treat_missing_data = "notBreaching"
|
||||
dimensions = {
|
||||
CacheClusterId = var.redis-cluster-id
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.36.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
variable "cw-alarm-prefix" {}
|
||||
variable "actions-enabled" {}
|
||||
variable "redis-cluster-id" {}
|
||||
variable "settings" {}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Monitoring module
|
||||
This module deploys the default cloudwatch metric monitoring
|
||||
|
||||
## Notes
|
||||
Terraform lifecycle ignores tags to speed up terraform subsequent update. Cloudwatch alarm tags cannot be read on aws console anyway.
|
||||
|
||||
## Example
|
||||
```terraform
|
||||
module "tgw" {
|
||||
source = "../../modules/util/resource-list"
|
||||
resource-type = "tgw"
|
||||
}
|
||||
|
||||
module "tgw-monitoring" {
|
||||
cw-alarm-prefix = local.cw-alarm-prefix
|
||||
for_each = module.tgw.result-set
|
||||
source = "../../modules/ManagementGovernance/Monitoring.TGW"
|
||||
default-tags = local.default-tags
|
||||
job-flow-id = split("/", each.value)[1]
|
||||
threshold-PacketDropCountNoRoute = 1
|
||||
actions-enabled = var.actions-enabled
|
||||
sns-targets = var.sns-targets
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,19 @@
|
||||
resource "aws_cloudwatch_metric_alarm" "tgw-PacketDropCountNoRoute" {
|
||||
for_each = var.settings
|
||||
alarm_name = "${each.value["ecccode"]}-TGW_${var.tgw-id}-PacketDropCountNoRoute"
|
||||
comparison_operator = each.value["comparison_operator"]
|
||||
evaluation_periods = each.value["evaluation_periods"]
|
||||
metric_name = each.value["metric"]
|
||||
period = each.value["period"]
|
||||
statistic = each.value["statistic"]
|
||||
threshold = each.value["threshold"]
|
||||
alarm_description = "TGW:${each.value["metric"]}"
|
||||
namespace = "AWS/TransitGateway"
|
||||
insufficient_data_actions = []
|
||||
actions_enabled = var.actions-enabled
|
||||
alarm_actions = [each.value["action"]]
|
||||
ok_actions = [each.value["action"]]
|
||||
dimensions = {
|
||||
TransitGateway = var.tgw-id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.47.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
variable cw-alarm-prefix {}
|
||||
variable actions-enabled {}
|
||||
variable tgw-id {}
|
||||
variable settings {}
|
||||
@@ -0,0 +1,47 @@
|
||||
<!-- This readme file is generated with terraform-docs -->
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | >= 1.3.0 |
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_sns_topic.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic) | resource |
|
||||
| [aws_sns_topic_subscription.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic_subscription) | resource |
|
||||
| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
|
||||
| [aws_region.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| email-addresses | Email recipients of SNS notifications | `set(string)` | n/a | yes |
|
||||
| kms-key-id | KMS key id for SNS topic at-rest encryption. Make sure the sender has access to this key | `string` | n/a | yes |
|
||||
| sender | ARN of SNS sender or sending service name | `string` | n/a | yes |
|
||||
| sender-type | Sender principal type. Value should be either *AWS* or *Service* | `string` | n/a | yes |
|
||||
| sns-topic-description | SNS topic display name | `string` | n/a | yes |
|
||||
| sns-topic-name | Name of SNS topic | `string` | n/a | yes |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| sns-topic-arn | n/a |
|
||||
|
||||
---
|
||||
## Authorship
|
||||
This module was developed by xpk.
|
||||
@@ -0,0 +1,69 @@
|
||||
data "aws_caller_identity" "this" {}
|
||||
data "aws_region" "this" {}
|
||||
|
||||
resource "aws_sns_topic" "this" {
|
||||
name = var.sns-topic-name
|
||||
display_name = var.sns-topic-description
|
||||
kms_master_key_id = var.kms-key-id
|
||||
policy = jsonencode(
|
||||
{
|
||||
"Version" : "2008-10-17",
|
||||
"Id" : "SnsTopicPolicy",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "SnsTopicAdmin",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"AWS" : data.aws_caller_identity.this.account_id
|
||||
},
|
||||
"Action" : [
|
||||
"SNS:GetTopicAttributes",
|
||||
"SNS:SetTopicAttributes",
|
||||
"SNS:AddPermission",
|
||||
"SNS:RemovePermission",
|
||||
"SNS:DeleteTopic",
|
||||
"SNS:Subscribe",
|
||||
"SNS:ListSubscriptionsByTopic",
|
||||
"SNS:Publish",
|
||||
"SNS:Receive"
|
||||
],
|
||||
"Resource" : "arn:aws:sns:${data.aws_region.this.name}:${data.aws_caller_identity.this.account_id}:${var.sns-topic-name}",
|
||||
"Condition" : {
|
||||
"StringEquals" : {
|
||||
"AWS:SourceOwner" : data.aws_caller_identity.this.account_id
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Sid" : "AllowPublishing",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"${var.sender-type}" : var.sender
|
||||
},
|
||||
"Action" : "sns:Publish",
|
||||
"Resource" : "arn:aws:sns:${data.aws_region.this.name}:${data.aws_caller_identity.this.account_id}:${var.sns-topic-name}"
|
||||
},
|
||||
{
|
||||
"Sid" : "AllowPublishThroughSSLOnly",
|
||||
"Action" : "SNS:Publish",
|
||||
"Effect" : "Deny",
|
||||
"Resource" : "arn:aws:sns:${data.aws_region.this.name}:${data.aws_caller_identity.this.account_id}:${var.sns-topic-name}",
|
||||
"Condition" : {
|
||||
"Bool" : {
|
||||
"aws:SecureTransport" : "false"
|
||||
}
|
||||
},
|
||||
"Principal" : "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
resource "aws_sns_topic_subscription" "this" {
|
||||
for_each = var.email-addresses
|
||||
topic_arn = aws_sns_topic.this.arn
|
||||
protocol = "email"
|
||||
endpoint = each.value
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
output "sns-topic-arn" {
|
||||
value = aws_sns_topic.this.arn
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
variable "sender" {
|
||||
type = string
|
||||
description = "ARN of SNS sender or sending service name"
|
||||
}
|
||||
|
||||
variable "sender-type" {
|
||||
type = string
|
||||
description = "Sender principal type. Value should be either *AWS* or *Service*"
|
||||
validation {
|
||||
condition = var.sender-type == "AWS" || var.sender-type == "Service"
|
||||
error_message = "Valid values are AWS or Service"
|
||||
}
|
||||
}
|
||||
|
||||
variable "sns-topic-name" {
|
||||
type = string
|
||||
description = "Name of SNS topic"
|
||||
}
|
||||
|
||||
variable "sns-topic-description" {
|
||||
type = string
|
||||
description = "SNS topic display name"
|
||||
}
|
||||
|
||||
variable "kms-key-id" {
|
||||
type = string
|
||||
description = "KMS key id for SNS topic at-rest encryption. Make sure the sender has access to this key"
|
||||
}
|
||||
|
||||
variable "email-addresses" {
|
||||
type = set(string)
|
||||
description = "Email recipients of SNS notifications"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user