diff --git a/README.md b/README.md
index e88c1a9..98563cc 100644
--- a/README.md
+++ b/README.md
@@ -116,6 +116,10 @@ Our custom Terraform modules are located in the `modules` directory. These modul
| [VPC](./modules/vpc/README.md) | Bootstrap a VPC for shared infrastructure. |
| [VPC Endpoint](./modules/vpc-endpoint/README.md) | Bootstrap VPC endpoints for S3, DynamoDB, and other services. |
+In case you need to create a new module, you can use the [Terraform Module Template](./modules/__template__/README.md) as a starting point.
+
+For reference, you can also check the [Terraform Registry](https://registry.terraform.io/) for additional modules.
+
## Apps and Services
In addition to infrastructure provisioning, we have included a few apps and services to help you get started. These are located in the `apps` directory and provide useful examples of how to use the infrastructure we have provisioned.
diff --git a/modules/__template__/README.md b/modules/__template__/README.md
new file mode 100644
index 0000000..301e2de
--- /dev/null
+++ b/modules/__template__/README.md
@@ -0,0 +1,38 @@
+# Terraform Module Template
+
+This is a template for creating Terraform modules. It includes a basic structure for organizing your module code and documentation.
+
+In this example, we show how to create an S3 bucket with versioning, encryption, logging, and lifecycle management. This module uses a customizable name prefix for all resources and allows extra tags to be assigned.
+
+## Key Highlights
+
+1. **`name` Variable**: Used as a prefix for all resources, providing an easy way to distinguish resources created by the module.
+2. **`tags` Variable**: Allows additional tags to be passed to the module, merged with the default tag structure.
+3. **Documentation**: The README clearly documents the purpose and examples of using the module.
+4. **Module Documentation**: The module documentation is generated using [terraform-docs](https://github.com/terraform-docs/terraform-docs) and provides detailed information about the module's inputs and outputs.
+
+## Usage
+
+```hcl
+module "s3_bucket" {
+ source = "path_to_your_module"
+
+ name = "data-lake"
+ bucket_name = "raw-data"
+ force_destroy = true
+ enable_versioning = true
+ kms_key_id = "alias/my-kms-key"
+ logging_bucket = "my-logging-bucket"
+
+ tags = {
+ Owner = "Anton"
+ Environment = "prod"
+ }
+}
+```
+
+## Module Documentation
+
+The module documentation is generated with [terraform-docs](https://github.com/terraform-docs/terraform-docs) by running `terraform-docs md . > ./docs/MODULE.md` from the module directory.
+
+You can also view the latest version of the module documentation [here](./docs/MODULE.md).
diff --git a/modules/__template__/docs/MODULE.md b/modules/__template__/docs/MODULE.md
new file mode 100644
index 0000000..952781a
--- /dev/null
+++ b/modules/__template__/docs/MODULE.md
@@ -0,0 +1,55 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 1.0 |
+| [aws](#requirement\_aws) | >= 5.0.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | >= 5.0.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_s3_bucket.bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
+| [aws_s3_bucket_lifecycle_configuration.lifecycle](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |
+| [aws_s3_bucket_logging.bucket_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |
+| [aws_s3_bucket_ownership_controls.ownership](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource |
+| [aws_s3_bucket_public_access_block.public_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
+| [aws_s3_bucket_server_side_encryption_configuration.sse](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |
+| [aws_s3_bucket_versioning.versioning](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [acl](#input\_acl) | Canned ACL to apply to the bucket | `string` | `"private"` | no |
+| [bucket\_name](#input\_bucket\_name) | The name of the S3 bucket | `string` | n/a | yes |
+| [enable\_lifecycle\_rule](#input\_enable\_lifecycle\_rule) | Enable lifecycle rule | `bool` | `true` | no |
+| [enable\_versioning](#input\_enable\_versioning) | Enable versioning on the S3 bucket | `bool` | `false` | no |
+| [force\_destroy](#input\_force\_destroy) | Force bucket deletion | `bool` | `false` | no |
+| [kms\_key\_id](#input\_kms\_key\_id) | KMS key for bucket encryption | `string` | `"alias/aws/s3"` | no |
+| [lifecycle\_expiration\_days](#input\_lifecycle\_expiration\_days) | Number of days after which to expire objects | `number` | `90` | no |
+| [lifecycle\_storage\_class](#input\_lifecycle\_storage\_class) | Storage class for lifecycle transition | `string` | `"GLACIER"` | no |
+| [lifecycle\_transition\_days](#input\_lifecycle\_transition\_days) | Number of days after which to transition objects | `number` | `30` | no |
+| [logging\_bucket](#input\_logging\_bucket) | Bucket for storing logs | `string` | n/a | yes |
+| [name](#input\_name) | Name to be used on all the resources as identifier | `string` | `""` | no |
+| [tags](#input\_tags) | Any extra tags to assign to objects | `map(any)` | `{}` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [bucket\_arn](#output\_bucket\_arn) | The ARN of the S3 bucket |
+| [bucket\_id](#output\_bucket\_id) | The ID of the S3 bucket |
+| [logging\_bucket](#output\_logging\_bucket) | The logging bucket for the S3 bucket |
+
\ No newline at end of file
diff --git a/modules/__template__/main.tf b/modules/__template__/main.tf
new file mode 100644
index 0000000..0a67294
--- /dev/null
+++ b/modules/__template__/main.tf
@@ -0,0 +1,69 @@
+resource "aws_s3_bucket" "bucket" {
+ bucket = "${var.name}-${var.bucket_name}"
+
+ force_destroy = var.force_destroy
+
+ tags = merge({
+ Name = "${var.name}-s3-bucket"
+ }, var.tags)
+}
+
+resource "aws_s3_bucket_ownership_controls" "ownership" {
+ bucket = aws_s3_bucket.bucket.id
+
+ rule {
+ object_ownership = "BucketOwnerEnforced"
+ }
+}
+
+resource "aws_s3_bucket_public_access_block" "public_access" {
+ bucket = aws_s3_bucket.bucket.id
+
+ block_public_acls = true
+ block_public_policy = true
+ restrict_public_buckets = true
+ ignore_public_acls = true
+}
+
+resource "aws_s3_bucket_versioning" "versioning" {
+ bucket = aws_s3_bucket.bucket.id
+
+ versioning_configuration {
+ status = var.enable_versioning ? "Enabled" : "Suspended"
+ }
+}
+
+resource "aws_s3_bucket_server_side_encryption_configuration" "sse" {
+ bucket = aws_s3_bucket.bucket.id
+
+ rule {
+ apply_server_side_encryption_by_default {
+ sse_algorithm = "aws:kms"
+ kms_master_key_id = var.kms_key_id
+ }
+ }
+}
+
+resource "aws_s3_bucket_lifecycle_configuration" "lifecycle" {
+ bucket = aws_s3_bucket.bucket.id
+
+ rule {
+ id = "default"
+ status = var.enable_lifecycle_rule ? "Enabled" : "Disabled"
+
+ transition {
+ days = var.lifecycle_transition_days
+ storage_class = var.lifecycle_storage_class
+ }
+
+ expiration {
+ days = var.lifecycle_expiration_days
+ }
+ }
+}
+
+resource "aws_s3_bucket_logging" "bucket_logging" {
+ bucket = aws_s3_bucket.bucket.id
+ target_bucket = var.logging_bucket
+ target_prefix = "${var.name}-${var.bucket_name}/logs/"
+}
diff --git a/modules/__template__/outputs.tf b/modules/__template__/outputs.tf
new file mode 100644
index 0000000..080506b
--- /dev/null
+++ b/modules/__template__/outputs.tf
@@ -0,0 +1,14 @@
+output "bucket_id" {
+ description = "The ID of the S3 bucket"
+ value = aws_s3_bucket.bucket.id
+}
+
+output "bucket_arn" {
+ description = "The ARN of the S3 bucket"
+ value = aws_s3_bucket.bucket.arn
+}
+
+output "logging_bucket" {
+ description = "The logging bucket for the S3 bucket"
+ value = aws_s3_bucket_logging.bucket_logging.target_bucket
+}
diff --git a/modules/__template__/variables.tf b/modules/__template__/variables.tf
new file mode 100644
index 0000000..aa1fe62
--- /dev/null
+++ b/modules/__template__/variables.tf
@@ -0,0 +1,69 @@
+variable "name" {
+ description = "Name to be used on all the resources as identifier"
+ type = string
+ default = ""
+}
+
+variable "tags" {
+ description = "Any extra tags to assign to objects"
+ type = map(any)
+ default = {}
+}
+
+variable "bucket_name" {
+ description = "The name of the S3 bucket"
+ type = string
+}
+
+variable "force_destroy" {
+ description = "Force bucket deletion"
+ type = bool
+ default = false
+}
+
+variable "acl" {
+ description = "Canned ACL to apply to the bucket"
+ type = string
+ default = "private"
+}
+
+variable "enable_versioning" {
+ description = "Enable versioning on the S3 bucket"
+ type = bool
+ default = false
+}
+
+variable "kms_key_id" {
+ description = "KMS key for bucket encryption"
+ type = string
+ default = "alias/aws/s3"
+}
+
+variable "enable_lifecycle_rule" {
+ description = "Enable lifecycle rule"
+ type = bool
+ default = true
+}
+
+variable "lifecycle_transition_days" {
+ description = "Number of days after which to transition objects"
+ type = number
+ default = 30
+}
+
+variable "lifecycle_storage_class" {
+ description = "Storage class for lifecycle transition"
+ type = string
+ default = "GLACIER"
+}
+
+variable "lifecycle_expiration_days" {
+ description = "Number of days after which to expire objects"
+ type = number
+ default = 90
+}
+
+variable "logging_bucket" {
+ description = "Bucket for storing logs"
+ type = string
+}
diff --git a/modules/__template__/versions.tf b/modules/__template__/versions.tf
new file mode 100644
index 0000000..729454b
--- /dev/null
+++ b/modules/__template__/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 5.0.0"
+ }
+ }
+}