diff --git a/README.md b/README.md
index 04be024..03e8863 100644
--- a/README.md
+++ b/README.md
@@ -4,14 +4,15 @@
This module consists of the following submodules:
-- [prometheus](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/prometheus)
-- [thanos](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/thanos)
-- [loki](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/loki)
-- [tempo](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/tempo)
-- [grafana](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/grafana)
-- [mimir](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/mimir)
+- [Prometheus](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/prometheus)
+- [Mimir](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/mimir)
+- [Thanos](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/thanos)
+- [Loki](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/loki)
+- [Tempo](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/tempo)
+- [Grafana](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/grafana)
- [AWS Managed Service for Prometheus](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/amp)
- [AWS Managed Grafana](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/amg)
- [AWS Distro for OpenTelemetry (ADOT) Operator](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/adot)
+- [CloudWatch](https://github.com/nlamirault/terraform-aws-observability/tree/master/modules/cloudwatch)
See more details in each module's README.
diff --git a/modules/cloudwatch/README.md b/modules/cloudwatch/README.md
new file mode 100644
index 0000000..951fb2c
--- /dev/null
+++ b/modules/cloudwatch/README.md
@@ -0,0 +1,53 @@
+# Observability / Cloudwatch
+
+Terraform module which configure Grafana Cloudwatch resources on Amazon AWS
+
+## Documentation
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 1.0.0 |
+| [aws](#requirement\_aws) | >= 4.0.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | >= 4.0.0 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [agent](#module\_agent) | terraform-aws-modules/iam/aws//modules/iam-assumable-role-with-oidc | 5.5.0 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_cloudwatch_log_group.cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
+| [aws_cloudwatch_log_group.container_insights](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
+| [aws_kms_alias.cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |
+| [aws_kms_key.cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |
+| [aws_eks_cluster.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/eks_cluster) | data source |
+| [aws_iam_policy.cloudwatch_agent_server](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [cluster\_name](#input\_cluster\_name) | Name of the EKS cluster | `string` | n/a | yes |
+| [deletion\_window\_in\_days](#input\_deletion\_window\_in\_days) | Duration in days after which the key is deleted after destruction of the resource, must be between 7 and 30 days | `number` | `30` | no |
+| [enable\_kms](#input\_enable\_kms) | Enable custom KMS key | `bool` | n/a | yes |
+| [log\_retention\_in\_days](#input\_log\_retention\_in\_days) | Number of days to retain log events | `number` | `90` | no |
+| [namespace](#input\_namespace) | The Kubernetes namespace | `string` | n/a | yes |
+| [service\_account](#input\_service\_account) | The Kubernetes service account | `string` | n/a | yes |
+| [tags](#input\_tags) | Tags for Cloudwatch | `map(string)` |
{
"Made-By": "Terraform"
}
| no |
+
+## Outputs
+
+No outputs.
+
diff --git a/modules/cloudwatch/agent.tf b/modules/cloudwatch/agent.tf
new file mode 100644
index 0000000..2f95814
--- /dev/null
+++ b/modules/cloudwatch/agent.tf
@@ -0,0 +1,32 @@
+# Copyright (C) Nicolas Lamirault
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module "agent" {
+ source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role-with-oidc"
+ version = "5.5.0"
+
+ create_role = true
+ role_description = "Cloudwatch Agent"
+ role_name = local.role_name
+ provider_url = data.aws_eks_cluster.this.identity[0].oidc[0].issuer
+ role_policy_arns = [
+ data.aws_iam_policy.cloudwatch_agent_server.arn
+ ]
+ oidc_fully_qualified_subjects = ["system:serviceaccount:${var.namespace}:${var.service_account}"]
+
+ tags = merge(
+ { "Name" = local.role_name },
+ var.tags
+ )
+}
diff --git a/modules/cloudwatch/data.tf b/modules/cloudwatch/data.tf
new file mode 100644
index 0000000..8d6bf41
--- /dev/null
+++ b/modules/cloudwatch/data.tf
@@ -0,0 +1,21 @@
+# Copyright (C) Nicolas Lamirault
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+data "aws_eks_cluster" "this" {
+ name = var.cluster_name
+}
+
+data "aws_iam_policy" "cloudwatch_agent_server" {
+ arn = "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
+}
diff --git a/modules/cloudwatch/locals.tf b/modules/cloudwatch/locals.tf
new file mode 100644
index 0000000..a020898
--- /dev/null
+++ b/modules/cloudwatch/locals.tf
@@ -0,0 +1,24 @@
+# Copyright (C) Nicolas Lamirault
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+locals {
+ role_name = "cloudwatch-agent"
+
+ container_insights_groups = [
+ "application",
+ "dataplane",
+ "host",
+ "performance"
+ ]
+}
diff --git a/modules/cloudwatch/log.tf b/modules/cloudwatch/log.tf
new file mode 100644
index 0000000..81204d7
--- /dev/null
+++ b/modules/cloudwatch/log.tf
@@ -0,0 +1,33 @@
+# Copyright (C) Nicolas Lamirault
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+resource "aws_cloudwatch_log_group" "cluster" {
+ name = format("/aws/eks/%s/cluster", data.aws_eks_cluster.id)
+ retention_in_days = var.log_retention_in_days
+
+ kms_key_id = var.enable_kms ? aws_kms_key.cloudwatch[0].arn : null
+
+ tags = var.tags
+}
+
+resource "aws_cloudwatch_log_group" "container_insights" {
+ for_each = local.container_insights_groups
+
+ name = format("/aws/containerinsights/%s/%s", data.aws_eks_cluster.id, each.key)
+ retention_in_days = var.log_retention_in_days
+
+ kms_key_id = var.enable_kms ? aws_kms_key.cloudwatch[0].arn : null
+
+ tags = var.tags
+}
diff --git a/modules/cloudwatch/main.tf b/modules/cloudwatch/main.tf
new file mode 100644
index 0000000..dd601ae
--- /dev/null
+++ b/modules/cloudwatch/main.tf
@@ -0,0 +1,24 @@
+# Copyright (C) Nicolas Lamirault
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+terraform {
+ required_version = ">= 1.0.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 4.0.0"
+ }
+ }
+}
diff --git a/modules/cloudwatch/outputs.tf b/modules/cloudwatch/outputs.tf
new file mode 100644
index 0000000..e65c150
--- /dev/null
+++ b/modules/cloudwatch/outputs.tf
@@ -0,0 +1,13 @@
+# Copyright (C) Nicolas Lamirault
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/modules/cloudwatch/variables.tf b/modules/cloudwatch/variables.tf
new file mode 100644
index 0000000..9c1e231
--- /dev/null
+++ b/modules/cloudwatch/variables.tf
@@ -0,0 +1,59 @@
+# Copyright (C) Nicolas Lamirault
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#############################################################################
+# Cloudwatch
+
+variable "cluster_name" {
+ type = string
+ description = "Name of the EKS cluster"
+}
+
+variable "log_retention_in_days" {
+ description = "Number of days to retain log events"
+ type = number
+ default = 90
+}
+
+variable "namespace" {
+ type = string
+ description = "The Kubernetes namespace"
+}
+
+variable "service_account" {
+ type = string
+ description = "The Kubernetes service account"
+}
+
+variable "tags" {
+ type = map(string)
+ description = "Tags for Cloudwatch"
+ default = {
+ Made-By = "Terraform"
+ }
+}
+
+#############################################################################
+# KMS
+
+variable "enable_kms" {
+ type = bool
+ description = "Enable custom KMS key"
+}
+
+variable "deletion_window_in_days" {
+ type = number
+ description = "Duration in days after which the key is deleted after destruction of the resource, must be between 7 and 30 days"
+ default = 30
+}