diff --git a/README.md b/README.md
index 6aaa2cf..ae5e6dc 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,58 @@
# terraform-aws-elasticsearch
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+
+## Providers
+
+No providers.
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [elasticsearch\_domain](#module\_elasticsearch\_domain) | ./modules/elasticsearch_domain | n/a |
+| [iam\_service\_linked\_role](#module\_iam\_service\_linked\_role) | ./modules/iam_service_linked_role | n/a |
+
+## Resources
+
+No resources.
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [create\_elasticsearch\_domain](#input\_create\_elasticsearch\_domain) | Determinator to create `elasticseach_domain` resources or not | `bool` | `true` | no |
+| [elasticsearch\_domain\_access\_policies](#input\_elasticsearch\_domain\_access\_policies) | IAM policy document specifying the access policies for the domain | `string` | `null` | no |
+| [elasticsearch\_domain\_advanced\_options](#input\_elasticsearch\_domain\_advanced\_options) | Key-value string pairs to specify advanced configuration options | `map(string)` | `{}` | no |
+| [elasticsearch\_domain\_advanced\_security\_options](#input\_elasticsearch\_domain\_advanced\_security\_options) | Configuration block for fine-grained access control | `any` | `{}` | no |
+| [elasticsearch\_domain\_auto\_tune\_options](#input\_elasticsearch\_domain\_auto\_tune\_options) | Configuration block for the Auto-Tune options of the domain | `any` | `{}` | no |
+| [elasticsearch\_domain\_cluster\_config](#input\_elasticsearch\_domain\_cluster\_config) | Configuration block for the cluster of the domain | `any` | `{}` | no |
+| [elasticsearch\_domain\_cognito\_options](#input\_elasticsearch\_domain\_cognito\_options) | Configuration block for authenticating Kibana with Cognito | `any` | `{}` | no |
+| [elasticsearch\_domain\_ebs\_options](#input\_elasticsearch\_domain\_ebs\_options) | Configuration block for EBS related options, may be required based on chosen instance size | `any` | `{}` | no |
+| [elasticsearch\_domain\_encrypt\_at\_rest](#input\_elasticsearch\_domain\_encrypt\_at\_rest) | Configuration block for encrypt at rest options. Only available for certain instance types | `any` | `{}` | no |
+| [elasticsearch\_domain\_endpoint\_options](#input\_elasticsearch\_domain\_endpoint\_options) | Configuration block for domain endpoint HTTP(S) related options | `any` | `{}` | no |
+| [elasticsearch\_domain\_log\_publishing\_options](#input\_elasticsearch\_domain\_log\_publishing\_options) | Configuration block for publishing slow and application logs to CloudWatch Logs | `any` | `{}` | no |
+| [elasticsearch\_domain\_name](#input\_elasticsearch\_domain\_name) | Required if `create_elasticsearch_domain` is set to `true`. Name of the domain | `string` | `null` | no |
+| [elasticsearch\_domain\_node\_to\_node\_encryption](#input\_elasticsearch\_domain\_node\_to\_node\_encryption) | Configuration block for node-to-node encryption options | `any` | `{}` | no |
+| [elasticsearch\_domain\_snapshot\_options](#input\_elasticsearch\_domain\_snapshot\_options) | Configuration block for snapshot related options | `any` | `{}` | no |
+| [elasticsearch\_domain\_tags](#input\_elasticsearch\_domain\_tags) | Map of tags to assign to the resource | `map(string)` | `{}` | no |
+| [elasticsearch\_domain\_version](#input\_elasticsearch\_domain\_version) | Version of Elasticsearch to deploy. Defaults to `1.5` | `string` | `"1.5"` | no |
+| [elasticsearch\_domain\_vpc\_options](#input\_elasticsearch\_domain\_vpc\_options) | Configuration block for VPC related options | `any` | `{}` | no |
+| [iam\_service\_linked\_roles](#input\_iam\_service\_linked\_roles) | The IAM Service linked roles where `aws_service_name` is a key | `any` | `{}` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [elasticsearch\_domain\_arn](#output\_elasticsearch\_domain\_arn) | ARN of the domain |
+| [elasticsearch\_domain\_endpoint](#output\_elasticsearch\_domain\_endpoint) | Domain-specific endpoint used to submit index, search, and data upload requests |
+| [elasticsearch\_domain\_id](#output\_elasticsearch\_domain\_id) | Unique identifier for the domain |
+| [elasticsearch\_domain\_kibana\_endpoint](#output\_elasticsearch\_domain\_kibana\_endpoint) | Domain-specific endpoint for kibana without https scheme |
+| [elasticsearch\_domain\_name](#output\_elasticsearch\_domain\_name) | Name of the Elasticsearch domain |
+| [iam\_service\_linked\_roles](#output\_iam\_service\_linked\_roles) | The IAM service linked roles |
\ No newline at end of file
diff --git a/main.tf b/main.tf
index e69de29..ce80bc5 100644
--- a/main.tf
+++ b/main.tf
@@ -0,0 +1,33 @@
+module "iam_service_linked_role" {
+ source = "./modules/iam_service_linked_role"
+
+ for_each = var.iam_service_linked_roles
+
+ aws_service_name = each.key
+ custom_suffix = lookup(each.value, "custom_suffix", null)
+ description = lookup(each.value, "description", null)
+ tags = lookup(each.value, "tags", null)
+}
+
+module "elasticsearch_domain" {
+ source = "./modules/elasticsearch_domain"
+
+ count = var.create_elasticsearch_domain ? 1 : 0
+
+ domain_name = var.elasticsearch_domain_name
+ access_policies = var.elasticsearch_domain_access_policies
+ advanced_options = var.elasticsearch_domain_advanced_options
+ elasticsearch_version = var.elasticsearch_domain_version
+ tags = var.elasticsearch_domain_tags
+ advanced_security_options = var.elasticsearch_domain_advanced_security_options
+ auto_tune_options = var.elasticsearch_domain_auto_tune_options
+ cluster_config = var.elasticsearch_domain_cluster_config
+ cognito_options = var.elasticsearch_domain_cognito_options
+ domain_endpoint_options = var.elasticsearch_domain_endpoint_options
+ ebs_options = var.elasticsearch_domain_ebs_options
+ encrypt_at_rest = var.elasticsearch_domain_encrypt_at_rest
+ log_publishing_options = var.elasticsearch_domain_log_publishing_options
+ node_to_node_encryption = var.elasticsearch_domain_node_to_node_encryption
+ snapshot_options = var.elasticsearch_domain_snapshot_options
+ vpc_options = var.elasticsearch_domain_vpc_options
+}
diff --git a/modules/elasticsearch_domain/.terraform.lock.hcl b/modules/elasticsearch_domain/.terraform.lock.hcl
new file mode 100644
index 0000000..4394b4d
--- /dev/null
+++ b/modules/elasticsearch_domain/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+ version = "4.14.0"
+ constraints = "~> 4.10"
+ hashes = [
+ "h1:wJ1F5KqM9XLQqotZ82YFQywpN4pwtVFR35uc5ckqGKw=",
+ "zh:00d03c06e6a7f8ccf8a5a8e03d71842ebe75c9bf4a94112429cf457ae50e9ec4",
+ "zh:1dc73df493294451a8a5bf80575d083958b8e33051f5a37764dcfd6264e0fd37",
+ "zh:4427e14bf3e1e0879f44edcf81a7091c67f7dd3c0b4a842f70ab2c5108452108",
+ "zh:4c9d8e627881207354020bcc2c6fede891d85a1893ee1a60c96e96f26bb792a7",
+ "zh:69c1dd3e8d1cfe85529d201ac6390df5e28bc353cf340b1ec3c5981d696f6373",
+ "zh:76df2d46384d7bf3c10e799145ee16c829f5bbf9218896aab4a73ec57dae0e90",
+ "zh:863ce9721e6d1f8554d77541545b6081e2afb1f38cb0c73a0491e58235ed588e",
+ "zh:9a8184398f83781623b2257361a1c038fb0eeb8361bb4714d1897f2479398b49",
+ "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+ "zh:bbf27af267e5a77780ccc83b2f79e75f47ce7b8ed4f864b34baad01cbf2f54fb",
+ "zh:f31cfa54f3951d4623a25712964724a57f491ab17b3944802d55072768b41043",
+ "zh:fe17dfac4954873faf340088949e2434058f6f6b2f228fe3e349527f1ecde92d",
+ ]
+}
diff --git a/modules/elasticsearch_domain/README.md b/modules/elasticsearch_domain/README.md
new file mode 100644
index 0000000..dc7d32c
--- /dev/null
+++ b/modules/elasticsearch_domain/README.md
@@ -0,0 +1,59 @@
+# Module: aws_elasticsearch_domain
+
+Manages an AWS Elasticsearch Domain.
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.10 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 4.14.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_elasticsearch_domain.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticsearch_domain) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [access\_policies](#input\_access\_policies) | IAM policy document specifying the access policies for the domain | `string` | `null` | no |
+| [advanced\_options](#input\_advanced\_options) | Key-value string pairs to specify advanced configuration options | `map(string)` | `{}` | no |
+| [advanced\_security\_options](#input\_advanced\_security\_options) | Configuration block for fine-grained access control | `any` | `{}` | no |
+| [auto\_tune\_options](#input\_auto\_tune\_options) | Configuration block for the Auto-Tune options of the domain | `any` | `{}` | no |
+| [cluster\_config](#input\_cluster\_config) | Configuration block for the cluster of the domain | `any` | `{}` | no |
+| [cognito\_options](#input\_cognito\_options) | Configuration block for authenticating Kibana with Cognito | `any` | `{}` | no |
+| [domain\_endpoint\_options](#input\_domain\_endpoint\_options) | Configuration block for domain endpoint HTTP(S) related options | `any` | `{}` | no |
+| [domain\_name](#input\_domain\_name) | Name of the domain | `string` | n/a | yes |
+| [ebs\_options](#input\_ebs\_options) | Configuration block for EBS related options, may be required based on chosen instance size | `any` | `{}` | no |
+| [elasticsearch\_version](#input\_elasticsearch\_version) | Version of Elasticsearch to deploy. Defaults to `1.5` | `string` | `"1.5"` | no |
+| [encrypt\_at\_rest](#input\_encrypt\_at\_rest) | Configuration block for encrypt at rest options. Only available for certain instance types | `any` | `{}` | no |
+| [log\_publishing\_options](#input\_log\_publishing\_options) | Configuration block for publishing slow and application logs to CloudWatch Logs | `any` | `{}` | no |
+| [node\_to\_node\_encryption](#input\_node\_to\_node\_encryption) | Configuration block for node-to-node encryption options | `any` | `{}` | no |
+| [snapshot\_options](#input\_snapshot\_options) | Configuration block for snapshot related options | `any` | `{}` | no |
+| [tags](#input\_tags) | Map of tags to assign to the resource | `map(string)` | `{}` | no |
+| [vpc\_options](#input\_vpc\_options) | Configuration block for VPC related options | `any` | `{}` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [arn](#output\_arn) | ARN of the domain |
+| [domain\_id](#output\_domain\_id) | Unique identifier for the domain |
+| [domain\_name](#output\_domain\_name) | Name of the Elasticsearch domain |
+| [endpoint](#output\_endpoint) | Domain-specific endpoint used to submit index, search, and data upload requests |
+| [kibana\_endpoint](#output\_kibana\_endpoint) | Domain-specific endpoint for kibana without https scheme |
+
\ No newline at end of file
diff --git a/modules/elasticsearch_domain/main.tf b/modules/elasticsearch_domain/main.tf
new file mode 100644
index 0000000..fbca63e
--- /dev/null
+++ b/modules/elasticsearch_domain/main.tf
@@ -0,0 +1,164 @@
+resource "aws_elasticsearch_domain" "this" {
+ domain_name = var.domain_name
+ access_policies = var.access_policies
+ advanced_options = var.advanced_options
+ elasticsearch_version = var.elasticsearch_version
+ tags = var.tags
+
+ dynamic "advanced_security_options" {
+ for_each = var.advanced_security_options != {} ? [var.advanced_security_options] : []
+
+ content {
+ enabled = advanced_security_options.value["enabled"]
+ internal_user_database_enabled = try(advanced_security_options.value["internal_user_database_enabled"], false)
+
+ dynamic "master_user_options" {
+ for_each = try(advanced_security_options.value["master_user_options"], {}) != {} ? [advanced_security_options.value["master_user_options"]] : []
+
+ content {
+ master_user_arn = try(master_user_options.value["master_user_arn"], null)
+ master_user_name = try(master_user_options.value["master_user_name"], null)
+ master_user_password = try(master_user_options.value["master_user_password"], null)
+ }
+ }
+ }
+ }
+
+ dynamic "auto_tune_options" {
+ for_each = var.auto_tune_options != {} ? [var.auto_tune_options] : []
+
+ content {
+ desired_state = auto_tune_options.value["desired_state"]
+ rollback_on_disable = try(auto_tune_options.value["rollback_on_disable"], null)
+
+ dynamic "maintenance_schedule" {
+ for_each = try(auto_tune_options.value["maintenance_schedule"], {}) != {} ? [auto_tune_options.value["maintenance_schedule"]] : []
+
+ content {
+ start_at = maintenance_schedule.value["start_at"]
+ cron_expression_for_recurrence = maintenance_schedule.value["cron_expression_for_recurrence"]
+
+ dynamic "duration" {
+ for_each = [maintenance_schedule.value["duration"]]
+
+ content {
+ value = duration.value["value"]
+ unit = duration.value["unit"]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ dynamic "cluster_config" {
+ for_each = var.cluster_config != {} ? [var.cluster_config] : []
+
+ content {
+ dedicated_master_count = try(cluster_config.value["dedicated_master_count"], null)
+ dedicated_master_enabled = try(cluster_config.value["dedicated_master_enabled"], null)
+ dedicated_master_type = try(cluster_config.value["dedicated_master_type"], null)
+ instance_count = try(cluster_config.value["instance_count"], null)
+ instance_type = try(cluster_config.value["instance_type"], null)
+ warm_count = try(cluster_config.value["warm_count"], null)
+ warm_enabled = try(cluster_config.value["warm_enabled"], null)
+ warm_type = try(cluster_config.value["warm_type"], null)
+ zone_awareness_enabled = try(cluster_config.value["zone_awareness_enabled"], null)
+
+ dynamic "cold_storage_options" {
+ for_each = try(cluster_config.value["cold_storage_options"], {}) != {} ? [cluster_config.value["cold_storage_options"]] : []
+
+ content {
+ enabled = try(cold_storage_options.value["enabled"], false)
+ }
+ }
+
+ dynamic "zone_awareness_config" {
+ for_each = try(cluster_config.value["zone_awareness_config"], {}) != {} ? [cluster_config.value["zone_awareness_config"]] : []
+
+ content {
+ availability_zone_count = try(zone_awareness_config.value["availability_zone_count"], 2)
+ }
+ }
+
+ }
+ }
+
+ dynamic "cognito_options" {
+ for_each = var.cognito_options != {} ? [var.cognito_options] : []
+
+ content {
+ identity_pool_id = cognito_options.value["identity_pool_id"]
+ role_arn = cognito_options.value["role_arn"]
+ user_pool_id = cognito_options.value["user_pool_id"]
+ enabled = try(cognito_options.value["enabled"], false)
+ }
+ }
+
+ dynamic "domain_endpoint_options" {
+ for_each = var.domain_endpoint_options != {} ? [var.domain_endpoint_options] : []
+
+ content {
+ custom_endpoint_certificate_arn = try(domain_endpoint_options.value["custom_endpoint_certificate_arn"], null)
+ custom_endpoint_enabled = try(domain_endpoint_options.value["custom_endpoint_enabled"], null)
+ custom_endpoint = try(domain_endpoint_options.value["custom_endpoint"], null)
+ enforce_https = try(domain_endpoint_options.value["enforce_https"], true)
+ tls_security_policy = try(domain_endpoint_options.value["tls_security_policy"], null)
+ }
+ }
+
+ dynamic "ebs_options" {
+ for_each = var.ebs_options != {} ? [var.ebs_options] : []
+
+ content {
+ ebs_enabled = ebs_options.value["ebs_enabled"]
+ iops = try(ebs_options.value["iops"], null)
+ volume_size = try(ebs_options.value["volume_size"], null)
+ volume_type = try(ebs_options.value["volume_type"], null)
+ }
+ }
+
+ dynamic "encrypt_at_rest" {
+ for_each = var.encrypt_at_rest != {} ? [var.encrypt_at_rest] : []
+
+ content {
+ enabled = encrypt_at_rest.value["enabled"]
+ kms_key_id = try(encrypt_at_rest.value["kms_key_id"], null)
+ }
+ }
+
+ dynamic "log_publishing_options" {
+ for_each = var.log_publishing_options #!= {} ? [var.log_publishing_options] : []
+
+ content {
+ log_type = log_publishing_options.key
+ cloudwatch_log_group_arn = log_publishing_options.value["cloudwatch_log_group_arn"]
+ enabled = try(log_publishing_options.value["enabled"], true)
+ }
+ }
+
+ dynamic "node_to_node_encryption" {
+ for_each = var.node_to_node_encryption != {} ? [var.node_to_node_encryption] : []
+
+ content {
+ enabled = node_to_node_encryption.value["enabled"]
+ }
+ }
+
+ dynamic "snapshot_options" {
+ for_each = var.snapshot_options != {} ? [var.snapshot_options] : []
+
+ content {
+ automated_snapshot_start_hour = snapshot_options.value["automated_snapshot_start_hour"]
+ }
+ }
+
+ dynamic "vpc_options" {
+ for_each = var.vpc_options != {} ? [var.vpc_options] : []
+
+ content {
+ subnet_ids = vpc_options.value["subnet_ids"]
+ security_group_ids = try(vpc_options.value["security_group_ids"], null)
+ }
+ }
+}
diff --git a/modules/elasticsearch_domain/outputs.tf b/modules/elasticsearch_domain/outputs.tf
new file mode 100644
index 0000000..5ac1b44
--- /dev/null
+++ b/modules/elasticsearch_domain/outputs.tf
@@ -0,0 +1,24 @@
+output "arn" {
+ description = "ARN of the domain"
+ value = aws_elasticsearch_domain.this.arn
+}
+
+output "domain_id" {
+ description = "Unique identifier for the domain"
+ value = aws_elasticsearch_domain.this.domain_id
+}
+
+output "domain_name" {
+ description = "Name of the Elasticsearch domain"
+ value = aws_elasticsearch_domain.this.domain_name
+}
+
+output "endpoint" {
+ description = "Domain-specific endpoint used to submit index, search, and data upload requests"
+ value = aws_elasticsearch_domain.this.endpoint
+}
+
+output "kibana_endpoint" {
+ description = "Domain-specific endpoint for kibana without https scheme"
+ value = aws_elasticsearch_domain.this.kibana_endpoint
+}
diff --git a/modules/elasticsearch_domain/terraform.tf b/modules/elasticsearch_domain/terraform.tf
new file mode 100644
index 0000000..879a279
--- /dev/null
+++ b/modules/elasticsearch_domain/terraform.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.10"
+ }
+ }
+}
diff --git a/modules/elasticsearch_domain/variables.tf b/modules/elasticsearch_domain/variables.tf
new file mode 100644
index 0000000..61e6858
--- /dev/null
+++ b/modules/elasticsearch_domain/variables.tf
@@ -0,0 +1,100 @@
+##########################################################################
+### REQUIRED
+##########################################################################
+variable "domain_name" {
+ description = "Name of the domain"
+ type = string
+}
+
+##########################################################################
+### OPTIONAL
+##########################################################################
+variable "access_policies" {
+ default = null
+ description = "IAM policy document specifying the access policies for the domain"
+ type = string
+}
+
+variable "advanced_options" {
+ default = {}
+ description = "Key-value string pairs to specify advanced configuration options"
+ type = map(string)
+}
+
+variable "advanced_security_options" {
+ default = {}
+ description = "Configuration block for fine-grained access control"
+ type = any
+}
+
+variable "auto_tune_options" {
+ default = {}
+ description = "Configuration block for the Auto-Tune options of the domain"
+ type = any
+}
+
+variable "cluster_config" {
+ default = {}
+ description = "Configuration block for the cluster of the domain"
+ type = any
+}
+
+variable "cognito_options" {
+ default = {}
+ description = "Configuration block for authenticating Kibana with Cognito"
+ type = any
+}
+
+variable "domain_endpoint_options" {
+ default = {}
+ description = "Configuration block for domain endpoint HTTP(S) related options"
+ type = any
+}
+
+variable "ebs_options" {
+ default = {}
+ description = "Configuration block for EBS related options, may be required based on chosen instance size"
+ type = any
+}
+
+variable "elasticsearch_version" {
+ default = "1.5"
+ description = "Version of Elasticsearch to deploy. Defaults to `1.5`"
+ type = string
+}
+
+variable "encrypt_at_rest" {
+ default = {}
+ description = "Configuration block for encrypt at rest options. Only available for certain instance types"
+ type = any
+}
+
+variable "log_publishing_options" {
+ default = {}
+ description = "Configuration block for publishing slow and application logs to CloudWatch Logs"
+ type = any
+}
+
+variable "node_to_node_encryption" {
+ default = {}
+ description = "Configuration block for node-to-node encryption options"
+ type = any
+}
+
+variable "snapshot_options" {
+ default = {}
+ description = "Configuration block for snapshot related options"
+ type = any
+}
+
+variable "tags" {
+ default = {}
+ description = "Map of tags to assign to the resource"
+ type = map(string)
+}
+
+variable "vpc_options" {
+ default = {}
+ description = "Configuration block for VPC related options"
+ type = any
+}
diff --git a/modules/iam_service_linked_role/.terraform.lock.hcl b/modules/iam_service_linked_role/.terraform.lock.hcl
new file mode 100644
index 0000000..4394b4d
--- /dev/null
+++ b/modules/iam_service_linked_role/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+ version = "4.14.0"
+ constraints = "~> 4.10"
+ hashes = [
+ "h1:wJ1F5KqM9XLQqotZ82YFQywpN4pwtVFR35uc5ckqGKw=",
+ "zh:00d03c06e6a7f8ccf8a5a8e03d71842ebe75c9bf4a94112429cf457ae50e9ec4",
+ "zh:1dc73df493294451a8a5bf80575d083958b8e33051f5a37764dcfd6264e0fd37",
+ "zh:4427e14bf3e1e0879f44edcf81a7091c67f7dd3c0b4a842f70ab2c5108452108",
+ "zh:4c9d8e627881207354020bcc2c6fede891d85a1893ee1a60c96e96f26bb792a7",
+ "zh:69c1dd3e8d1cfe85529d201ac6390df5e28bc353cf340b1ec3c5981d696f6373",
+ "zh:76df2d46384d7bf3c10e799145ee16c829f5bbf9218896aab4a73ec57dae0e90",
+ "zh:863ce9721e6d1f8554d77541545b6081e2afb1f38cb0c73a0491e58235ed588e",
+ "zh:9a8184398f83781623b2257361a1c038fb0eeb8361bb4714d1897f2479398b49",
+ "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+ "zh:bbf27af267e5a77780ccc83b2f79e75f47ce7b8ed4f864b34baad01cbf2f54fb",
+ "zh:f31cfa54f3951d4623a25712964724a57f491ab17b3944802d55072768b41043",
+ "zh:fe17dfac4954873faf340088949e2434058f6f6b2f228fe3e349527f1ecde92d",
+ ]
+}
diff --git a/modules/iam_service_linked_role/README.md b/modules/iam_service_linked_role/README.md
new file mode 100644
index 0000000..70c907f
--- /dev/null
+++ b/modules/iam_service_linked_role/README.md
@@ -0,0 +1,45 @@
+# Module: aws_iam_service_linked_role
+Provides an [IAM service-linked role.](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html)
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.10 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 4.14.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_service_linked_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_service_linked_role) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [aws\_service\_name](#input\_aws\_service\_name) | The AWS service to which this role is attached | `string` | n/a | yes |
+| [custom\_suffix](#input\_custom\_suffix) | Additional string appended to the role name | `string` | `null` | no |
+| [description](#input\_description) | The description of the role | `string` | `null` | no |
+| [tags](#input\_tags) | Key-value mapping of tags for the IAM role | `map(string)` | `{}` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [arn](#output\_arn) | The Amazon Resource Name (ARN) specifying the role |
+| [id](#output\_id) | The Amazon Resource Name (ARN) of the role |
+| [name](#output\_name) | The name of the role |
+| [path](#output\_path) | The path of the role |
+
\ No newline at end of file
diff --git a/modules/iam_service_linked_role/main.tf b/modules/iam_service_linked_role/main.tf
new file mode 100644
index 0000000..22e8100
--- /dev/null
+++ b/modules/iam_service_linked_role/main.tf
@@ -0,0 +1,6 @@
+resource "aws_iam_service_linked_role" "this" {
+ aws_service_name = var.aws_service_name
+ custom_suffix = var.custom_suffix
+ description = var.description
+ tags = var.tags
+}
diff --git a/modules/iam_service_linked_role/outputs.tf b/modules/iam_service_linked_role/outputs.tf
new file mode 100644
index 0000000..60dbaa0
--- /dev/null
+++ b/modules/iam_service_linked_role/outputs.tf
@@ -0,0 +1,19 @@
+output "id" {
+ description = "The Amazon Resource Name (ARN) of the role"
+ value = aws_iam_service_linked_role.this.id
+}
+
+output "arn" {
+ description = "The Amazon Resource Name (ARN) specifying the role"
+ value = aws_iam_service_linked_role.this.arn
+}
+
+output "name" {
+ description = "The name of the role"
+ value = aws_iam_service_linked_role.this.name
+}
+
+output "path" {
+ description = "The path of the role"
+ value = aws_iam_service_linked_role.this.name
+}
diff --git a/modules/iam_service_linked_role/terraform.tf b/modules/iam_service_linked_role/terraform.tf
new file mode 100644
index 0000000..879a279
--- /dev/null
+++ b/modules/iam_service_linked_role/terraform.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.10"
+ }
+ }
+}
diff --git a/modules/iam_service_linked_role/variables.tf b/modules/iam_service_linked_role/variables.tf
new file mode 100644
index 0000000..2ffdc93
--- /dev/null
+++ b/modules/iam_service_linked_role/variables.tf
@@ -0,0 +1,27 @@
+##########################################################################
+### REQUIRED
+##########################################################################
+variable "aws_service_name" {
+ description = "The AWS service to which this role is attached"
+ type = string
+}
+
+##########################################################################
+### OPTIONAL
+##########################################################################
+variable "custom_suffix" {
+ default = null
+ description = "Additional string appended to the role name"
+ type = string
+}
+variable "description" {
+ default = null
+ description = "The description of the role"
+ type = string
+}
+
+variable "tags" {
+ default = {}
+ description = "Key-value mapping of tags for the IAM role"
+ type = map(string)
+}
diff --git a/outputs.tf b/outputs.tf
index e69de29..c46e0fa 100644
--- a/outputs.tf
+++ b/outputs.tf
@@ -0,0 +1,35 @@
+##########################################################################
+### IAM SERVICE LINKED ROLE
+##########################################################################
+output "iam_service_linked_roles" {
+ description = "The IAM service linked roles"
+ value = { for k, v in var.iam_service_linked_roles : k => module.iam_service_linked_role[k] }
+}
+
+##########################################################################
+### ELASTICSEARCH DOMAIN
+##########################################################################
+output "elasticsearch_domain_arn" {
+ description = "ARN of the domain"
+ value = try(module.elasticsearch_domain[0].arn, "")
+}
+
+output "elasticsearch_domain_id" {
+ description = "Unique identifier for the domain"
+ value = try(module.elasticsearch_domain[0].domain_id, "")
+}
+
+output "elasticsearch_domain_name" {
+ description = "Name of the Elasticsearch domain"
+ value = try(module.elasticsearch_domain[0].domain_name, "")
+}
+
+output "elasticsearch_domain_endpoint" {
+ description = "Domain-specific endpoint used to submit index, search, and data upload requests"
+ value = try(module.elasticsearch_domain[0].endpoint, "")
+}
+
+output "elasticsearch_domain_kibana_endpoint" {
+ description = "Domain-specific endpoint for kibana without https scheme"
+ value = try(module.elasticsearch_domain[0].kibana_endpoint, "")
+}
diff --git a/variables.tf b/variables.tf
index e69de29..d7354bf 100644
--- a/variables.tf
+++ b/variables.tf
@@ -0,0 +1,113 @@
+##########################################################################
+### IAM SERVICE LINKED ROLE
+##########################################################################
+variable "iam_service_linked_roles" {
+ default = {}
+ description = "The IAM Service linked roles where `aws_service_name` is a key"
+ type = any
+}
+
+##########################################################################
+### ELASTICSEARCH DOMAIN
+##########################################################################
+variable "create_elasticsearch_domain" {
+ default = true
+ description = "Determinator to create `elasticseach_domain` resources or not"
+ type = bool
+}
+
+variable "elasticsearch_domain_name" {
+ default = null
+ description = "Required if `create_elasticsearch_domain` is set to `true`. Name of the domain"
+ type = string
+}
+
+variable "elasticsearch_domain_access_policies" {
+ default = null
+ description = "IAM policy document specifying the access policies for the domain"
+ type = string
+}
+
+variable "elasticsearch_domain_advanced_options" {
+ default = {}
+ description = "Key-value string pairs to specify advanced configuration options"
+ type = map(string)
+}
+
+variable "elasticsearch_domain_advanced_security_options" {
+ default = {}
+ description = "Configuration block for fine-grained access control"
+ type = any
+}
+
+variable "elasticsearch_domain_auto_tune_options" {
+ default = {}
+ description = "Configuration block for the Auto-Tune options of the domain"
+ type = any
+}
+
+variable "elasticsearch_domain_cluster_config" {
+ default = {}
+ description = "Configuration block for the cluster of the domain"
+ type = any
+}
+
+variable "elasticsearch_domain_cognito_options" {
+ default = {}
+ description = "Configuration block for authenticating Kibana with Cognito"
+ type = any
+}
+
+variable "elasticsearch_domain_endpoint_options" {
+ default = {}
+ description = "Configuration block for domain endpoint HTTP(S) related options"
+ type = any
+}
+
+variable "elasticsearch_domain_ebs_options" {
+ default = {}
+ description = "Configuration block for EBS related options, may be required based on chosen instance size"
+ type = any
+}
+
+variable "elasticsearch_domain_version" {
+ default = "1.5"
+ description = "Version of Elasticsearch to deploy. Defaults to `1.5`"
+ type = string
+}
+
+variable "elasticsearch_domain_encrypt_at_rest" {
+ default = {}
+ description = "Configuration block for encrypt at rest options. Only available for certain instance types"
+ type = any
+}
+
+variable "elasticsearch_domain_log_publishing_options" {
+ default = {}
+ description = "Configuration block for publishing slow and application logs to CloudWatch Logs"
+ type = any
+}
+
+variable "elasticsearch_domain_node_to_node_encryption" {
+ default = {}
+ description = "Configuration block for node-to-node encryption options"
+ type = any
+}
+
+variable "elasticsearch_domain_snapshot_options" {
+ default = {}
+ description = "Configuration block for snapshot related options"
+ type = any
+}
+
+variable "elasticsearch_domain_tags" {
+ default = {}
+ description = "Map of tags to assign to the resource"
+ type = map(string)
+}
+
+variable "elasticsearch_domain_vpc_options" {
+ default = {}
+ description = "Configuration block for VPC related options"
+ type = any
+}