diff --git a/functions.tf b/functions.tf
new file mode 100644
index 0000000000000000000000000000000000000000..50d092090a5b95ca007ca3dabef2455f264b8c55
--- /dev/null
+++ b/functions.tf
@@ -0,0 +1,180 @@
+locals {
+  function_name_prefix = local.Name
+  functions = [
+    "_dns",
+  ]
+}
+
+data "aws_iam_policy_document" "lambda_assume_policy" {
+  statement {
+    effect  = "Allow"
+    actions = ["sts:AssumeRole"]
+
+    principals {
+      type        = "Service"
+      identifiers = ["lambda.amazonaws.com"]
+    }
+  }
+}
+
+locals {
+  lambda_assume_policy_doc = data.aws_iam_policy_document.lambda_assume_policy.json
+}
+
+resource "aws_iam_role" "lambda" {
+  name               = local.Name
+  assume_role_policy = local.lambda_assume_policy_doc
+  tags               = local.common_tags
+}
+
+locals {
+  lambda_role_arn  = aws_iam_role.lambda.arn
+  lambda_role_name = aws_iam_role.lambda.name
+}
+
+output "lambda_role_arn" {
+  description = "ARN of the Lambda function IAM role."
+  value       = local.lambda_role_arn
+}
+
+output "lambda_role_name" {
+  description = "Name of the Lambda function IAM role."
+  value       = local.lambda_role_name
+}
+
+locals {
+  function_role_policies = [
+    local.publish_policy_arn,
+    #local.log_policy_arn,
+    "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
+  ]
+}
+
+resource "aws_iam_role_policy_attachment" "function" {
+  count      = length(local.function_role_policies)
+  role       = local.lambda_role_name
+  policy_arn = local.function_role_policies[count.index]
+}
+
+variable "runtime" {
+  default     = "python3.8"
+  description = "The Lambda function runtime."
+  type        = string
+}
+
+output "runtime" {
+  description = "The Lambda function runtime."
+  value       = var.runtime
+}
+
+variable "memory_size" {
+  default     = 128
+  description = "Amount of memory in MB allocated to the function invocation."
+  type        = number
+}
+
+output "memory_size" {
+  description = "Amount of memory in MB allocated to the function invocation."
+  value       = var.memory_size
+}
+
+variable "timeout" {
+  default     = 30
+  description = "Amouyynt of time in seconds the function has to run."
+  type        = number
+}
+
+output "timeout" {
+  description = "Amount of memory in MB allocated to the function invocation."
+  value       = var.timeout
+}
+
+resource "aws_lambda_function" "function" {
+  count             = length(local.functions)
+  runtime           = var.runtime
+  function_name     = "${local.function_name_prefix}_${local.functions[count.index]}"
+  role              = local.lambda_role_arn
+  source_code_hash  = filebase64sha256("payload.zip")
+  s3_bucket         = local.payloads_bucket_name
+  s3_key            = local.payload_object_name
+  s3_object_version = local.payload_object_version
+  package_type      = "Zip"
+  handler           = "${local.functions[count.index]}.handler"
+  description       = "${local.module} ${local.functions[count.index]} check in ${local.env}."
+  memory_size       = var.memory_size
+  tags              = local.common_tags
+  timeout           = var.timeout
+
+  environment {
+    variables = {
+      ENV       = local.env
+      MODULE    = local.module
+      TOPIC_ARN = local.topic_arn
+      VERSION   = local.payload_object_version
+    }
+  }
+
+  # Create the log group with retention before the function is created.
+  # Otherwise it's created without retention and need to be imported.
+  depends_on = [
+    aws_cloudwatch_log_group.lambda,
+  ]
+}
+
+locals {
+  function_arns     = aws_lambda_function.function.*.arn
+  function_names    = aws_lambda_function.function.*.id
+  function_versions = aws_lambda_function.function.*.version
+}
+
+output "function_arns" {
+  description = "ARNs of the Lambda functions."
+  value       = local.function_arns
+}
+
+output "function_names" {
+  description = "Names of the Lambda functions."
+  value       = local.function_names
+}
+
+output "function_versions" {
+  description = "Versions of the Lambda functions."
+  value       = local.function_versions
+}
+
+output "function_version_mapping" {
+  description = "Mapping of the function and version."
+  value       = zipmap(local.functions, local.function_versions)
+}
+
+resource "aws_lambda_alias" "function" {
+  count            = length(local.functions)
+  name             = "${local.function_name_prefix}_${local.functions[count.index]}"
+  function_name    = local.function_arns[count.index]
+  function_version = local.function_versions[count.index]
+}
+
+locals {
+  function_alias_arns  = aws_lambda_alias.function.*.arn
+  function_alias_names = aws_lambda_alias.function.*.name
+}
+
+output "function_alias_arns" {
+  description = "ARNs of the Lambda functions aliases."
+  value       = local.function_alias_arns
+}
+
+output "function_alias_names" {
+  description = "Names of the Lambda functions aliases."
+  value       = local.function_alias_names
+}
+
+resource "aws_lambda_permission" "cloudwatch" {
+  count         = length(local.function_arns)
+  statement_id  = "AllowExecutionFromCloudWatch"
+  action        = "lambda:InvokeFunction"
+  principal     = "events.amazonaws.com"
+  source_arn    = local.cloudwatch_rule_arn
+  function_name = local.function_names[count.index]
+  qualifier     = local.function_alias_names[count.index]
+}
diff --git a/log-groups.tf b/log-groups.tf
new file mode 100644
index 0000000000000000000000000000000000000000..e74ed2647a95f8fda7889f64af380c0797dc553d
--- /dev/null
+++ b/log-groups.tf
@@ -0,0 +1,59 @@
+resource "aws_cloudwatch_log_group" "lambda" {
+  count             = length(local.functions)
+  name              = "/aws/lambda/${local.function_name_prefix}_${local.functions[count.index]}"
+  retention_in_days = var.log_retention
+  tags              = local.common_tags
+}
+
+locals {
+  log_group_arns  = aws_cloudwatch_log_group.lambda.*.arn
+  log_group_names = aws_cloudwatch_log_group.lambda.*.name
+}
+
+output "log_group_arns" {
+  description = "ARNs of the CloudWatch log groups for Lambda function invocations."
+  value       = local.log_group_arns
+}
+
+output "log_group_names" {
+  description = "Names of the CloudWatch log groups for Lambda function invocations."
+  value       = local.log_group_names
+}
+
+data "aws_iam_policy_document" "log" {
+  statement {
+    effect = "Allow"
+
+    actions = [
+      "logs:CreateLogStream",
+      "logs:PutLogEvents",
+    ]
+
+    resources = [for arn in local.log_group_arns : "${arn}/*"]
+  }
+}
+
+locals {
+  log_policy_doc = data.aws_iam_policy_document.log.json
+}
+
+resource "aws_iam_policy" "log" {
+  name   = "${local.module}-${local.env}-log"
+  policy = local.log_policy_doc
+  tags   = local.common_tags
+}
+
+locals {
+  log_policy_arn  = aws_iam_policy.log.arn
+  log_policy_name = aws_iam_policy.log.name
+}
+
+output "log_policy_arn" {
+  value       = local.log_policy_arn
+  description = "CloudWatch log IAM policy ARN."
+}
+
+output "log_policy_name" {
+  value       = local.log_policy_name
+  description = "CloudWatch log IAM policy name."
+}
diff --git a/main.tf b/main.tf
index e156d2da3eb1b339daa38391dfa86efda8ea5f30..89281085e6d01641e18af3c1ac276f244e92ec48 100644
--- a/main.tf
+++ b/main.tf
@@ -12,8 +12,72 @@ locals {
   Name = "${local.module}-${local.env}"
 }
 
+output "env" {
+  description = "Environment (prod/dev etc.)."
+  value       = local.env
+}
+
+output "module" {
+  description = "The name of the Terraform module, used to tagging resources."
+  value       = local.module
+}
+
+variable "region" {
+  default     = "us-east-1"
+  description = "AWS region."
+  type        = string
+}
+
+output "region" {
+  description = "AWS region."
+  value       = var.region
+}
+
 provider "aws" {
   region = var.region
 }
 
-provider "template" {}
+resource "aws_resourcegroups_group" "group" {
+  name = local.Name
+  tags = local.common_tags
+  resource_query {
+    query = <<EOF
+{
+  "ResourceTypeFilters": [
+    "AWS::AllSupported"
+  ],
+  "TagFilters": [
+    {
+      "Key": "Module",
+      "Values": ["${local.module}"]
+    },
+    {
+      "Key": "Environment",
+      "Values": ["${local.env}"]
+    }
+  ]
+}
+EOF
+  }
+}
+
+locals {
+  resource_group_arn  = aws_resourcegroups_group.group.arn
+  resource_group_name = aws_resourcegroups_group.group.name
+}
+
+output "resource_group_arn" {
+  description = "ARN of the resource group."
+  value       = local.resource_group_arn
+}
+
+output "resource_group_name" {
+  description = "Name of the resource group."
+  value       = local.resource_group_name
+}
+
+variable "log_retention" {
+  default     = 3
+  description = "Number of days to retain logs."
+  type        = number
+}
diff --git a/outputs.tf b/outputs.tf
deleted file mode 100644
index 13939773a216a404c2939332f1ff578a0f8570d6..0000000000000000000000000000000000000000
--- a/outputs.tf
+++ /dev/null
@@ -1,14 +0,0 @@
-output "env" {
-  description = "Environment (prod/dev etc.)."
-  value       = local.env
-}
-
-output "module" {
-  description = "The name of the Terraform module, used to tagging resources."
-  value       = local.module
-}
-
-output "region" {
-  description = "AWS region."
-  value       = var.region
-}
diff --git a/s3.tf b/s3.tf
new file mode 100644
index 0000000000000000000000000000000000000000..23aab352a5400c059a6fc2e54668d5e000977e27
--- /dev/null
+++ b/s3.tf
@@ -0,0 +1,53 @@
+resource "aws_s3_bucket" "payloads" {
+  bucket = local.Name
+  tags   = local.common_tags
+  acl    = "private"
+
+  versioning {
+    enabled = true
+  }
+}
+
+locals {
+  payloads_bucket_arn  = aws_s3_bucket.payloads.arn
+  payloads_bucket_name = aws_s3_bucket.payloads.bucket
+}
+
+output "payloads_bucket_arn" {
+  description = "ARN of the payloads S3 bucket."
+  value       = local.payloads_bucket_arn
+}
+
+output "payloads_bucket_name" {
+  description = "Name of the payloads S3 bucket."
+  value       = local.payloads_bucket_name
+}
+
+resource "aws_s3_bucket_object" "payload" {
+  bucket = local.payloads_bucket_name
+  key    = "${local.env}/payload.zip"
+  source = "payload.zip"
+  etag   = filemd5("payload.zip")
+  tags   = local.common_tags
+}
+
+locals {
+  payload_object_etag    = aws_s3_bucket_object.payload.etag
+  payload_object_name    = aws_s3_bucket_object.payload.key
+  payload_object_version = aws_s3_bucket_object.payload.version_id
+}
+
+output "payload_object_etag" {
+  description = "ETag of the payload S3 object."
+  value       = local.payload_object_etag
+}
+
+output "payload_object_name" {
+  description = "Name of the payload S3 object."
+  value       = local.payload_object_name
+}
+
+output "payload_object_version" {
+  description = "Version of the payload S3 object."
+  value       = local.payload_object_version
+}
diff --git a/sns.tf b/sns.tf
index 6e489495df3c5ec44e8b77290217aec708a15e88..725e2e56dbfd217070759383b159c1cfe987eddb 100644
--- a/sns.tf
+++ b/sns.tf
@@ -42,17 +42,7 @@ data "aws_iam_policy_document" "publish" {
     effect = "Allow"
 
     actions = [
-      "SNS:ListTopics"
-    ]
-
-    resources = ["*"]
-  }
-
-  statement {
-    effect = "Allow"
-
-    actions = [
-      "SNS:Publish"
+      "SNS:Publish",
     ]
 
     resources = [
diff --git a/triggers.tf b/triggers.tf
new file mode 100644
index 0000000000000000000000000000000000000000..d35c5c5b1ff4970f2e467152bad84bc4761f16ad
--- /dev/null
+++ b/triggers.tf
@@ -0,0 +1,41 @@
+variable "rate" {
+  default     = 15
+  description = "How often in minutes the Lambda functions will trigger."
+  type        = number
+}
+
+output "rate" {
+  description = "How often in minutes the Lambda functions will trigger."
+  value       = var.rate
+}
+
+resource "aws_cloudwatch_event_rule" "schedule" {
+  name                = local.Name
+  description         = "Schedule to trigger ${local.module} functions in ${local.env}."
+  schedule_expression = "rate(${var.rate} minutes)"
+  tags                = local.common_tags
+}
+
+locals {
+  cloudwatch_rule_arn  = aws_cloudwatch_event_rule.schedule.arn
+  cloudwatch_rule_name = aws_cloudwatch_event_rule.schedule.name
+}
+
+output "cloudwatch_rule_arn" {
+  description = "ARN of the CloudWatch schedule rule."
+  value       = local.cloudwatch_rule_arn
+}
+
+output "cloudwatch_rule_name" {
+  description = "Name of the CloudWatch schedule rule."
+  value       = local.cloudwatch_rule_name
+}
+
+resource "aws_cloudwatch_event_target" "schedule" {
+  count = length(local.function_arns)
+  arn   = local.function_alias_arns[count.index]
+  rule  = local.cloudwatch_rule_name
+  depends_on = [
+    aws_lambda_permission.cloudwatch,
+  ]
+}
diff --git a/variables.tf b/variables.tf
deleted file mode 100644
index d86dca0c21cc789a387837174173aea52841ead1..0000000000000000000000000000000000000000
--- a/variables.tf
+++ /dev/null
@@ -1,4 +0,0 @@
-variable "region" {
-  default     = "us-east-1"
-  description = "AWS region."
-}