Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions examples/basic/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,13 @@ locals {
module "lambdacron" {
source = "../.."

aws_region = var.aws_region
lambda_image_uri = local.active_lambda_image_uri
schedule_expression = var.schedule_expression
lambda_name = var.lambda_name
create_test_url = var.create_test_url
aws_region = var.aws_region
lambda_image_uri = local.active_lambda_image_uri
schedule_expression = var.schedule_expression
lambda_name = var.lambda_name
create_test_url = var.create_test_url
scheduled_lambda_additional_managed_policy_arns = var.scheduled_lambda_additional_managed_policy_arns
scheduled_lambda_additional_inline_policies = var.scheduled_lambda_additional_inline_policies

tags = local.common_tags
}
Expand Down
12 changes: 12 additions & 0 deletions examples/basic/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ variable "create_test_url" {
default = false
}

variable "scheduled_lambda_additional_managed_policy_arns" {
description = "Additional IAM managed policy ARNs to attach to the scheduled Lambda execution role, keyed by stable labels."
type = map(string)
default = {}
}

variable "scheduled_lambda_additional_inline_policies" {
description = "Additional inline IAM policy JSON documents to attach to the scheduled Lambda execution role, keyed by stable labels."
type = map(string)
default = {}
}

variable "email_sender" {
description = "Sender email address for the SES notifier."
type = string
Expand Down
14 changes: 8 additions & 6 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ module "scheduled_lambda" {
schedule_expression = var.schedule_expression
sns_topic_arn = aws_sns_topic.results.arn

lambda_env = var.lambda_env
timeout = var.timeout
memory_size = var.memory_size
lambda_name = var.lambda_name
image_command = var.image_command
create_test_url = var.create_test_url
lambda_env = var.lambda_env
timeout = var.timeout
memory_size = var.memory_size
lambda_name = var.lambda_name
image_command = var.image_command
create_test_url = var.create_test_url
additional_managed_policy_arns = var.scheduled_lambda_additional_managed_policy_arns
additional_inline_policies = var.scheduled_lambda_additional_inline_policies

tags = local.tags
}
42 changes: 39 additions & 3 deletions modules/scheduled-lambda/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,52 @@ resource "aws_sns_topic" "results" {
name = "cloud-cron-results"
}

resource "aws_iam_policy" "terminate_instance" {
name = "allow-terminate-instance"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["ec2:TerminateInstances"]
Resource = ["arn:aws:ec2:us-west-2:123456789012:instance/i-0123456789abcdef0"]
}
]
})
}

data "aws_iam_policy_document" "describe_instances" {
statement {
effect = "Allow"
actions = ["ec2:DescribeInstances"]
resources = ["*"]
}
}

module "scheduled_lambda" {
source = "./modules/scheduled-lambda"

lambda_image_uri = "123456789012.dkr.ecr.us-west-2.amazonaws.com/my-lambda:latest"
schedule_expression = "rate(5 minutes)"
sns_topic_arn = aws_sns_topic.results.arn
lambda_image_uri = "123456789012.dkr.ecr.us-west-2.amazonaws.com/my-lambda:latest"
schedule_expression = "rate(5 minutes)"
sns_topic_arn = aws_sns_topic.results.arn

lambda_env = {
LOG_LEVEL = "info"
}

additional_managed_policy_arns = {
terminate_instance = aws_iam_policy.terminate_instance.arn
}

additional_inline_policies = {
describe_instances = data.aws_iam_policy_document.describe_instances.json
}
}
```

The module's built-in CloudWatch Logs and SNS publish permissions are attached as an inline role policy, leaving the role's managed-policy attachment quota available for the caller's `additional_managed_policy_arns`. AWS still enforces the aggregate inline policy size limit for `additional_inline_policies`.

## Inputs

- `lambda_image_uri` (string): URI of the Lambda container image.
Expand All @@ -34,11 +67,14 @@ module "scheduled_lambda" {
- `image_command` (list(string)): Optional override for the container CMD/handler.
- `tags` (map(string)): Tags to apply to created resources.
- `create_test_url` (bool): Create a public Lambda Function URL for temporary testing only (not for production). This URL has no auth and is publicly accessible, so it can be abused.
- `additional_managed_policy_arns` (map(string)): Additional IAM managed policy ARNs to attach to the Lambda execution role, keyed by stable labels. Supports up to 10 entries.
- `additional_inline_policies` (map(string)): Additional inline IAM policy JSON documents to attach to the Lambda execution role, keyed by stable labels. AWS enforces the aggregate inline-policy size limit.
Comment on lines 56 to +71
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an incorrect statement. There's a limit of 10 managed policies, but you can have as many inline as your want (although there is a limit on total length.)

You can add as many inline policies as you want to an IAM user, role, or group.

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-quotas-entity-length


## Outputs

- `lambda_arn`: ARN of the scheduled Lambda function.
- `execution_role_arn`: ARN of the Lambda execution role.
- `execution_role_name`: Name of the Lambda execution role.
- `log_group_name`: CloudWatch log group name for the Lambda.
- `schedule_rule_name`: Name of the EventBridge schedule rule.
- `test_function_url`: Function URL for temporary testing (null if disabled).
18 changes: 14 additions & 4 deletions modules/scheduled-lambda/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,25 @@ resource "aws_iam_role" "lambda_role" {
tags = local.tags
}

resource "aws_iam_policy" "lambda_policy" {
resource "aws_iam_role_policy" "lambda_permissions" {
name = "${local.lambda_name}-permissions"
role = aws_iam_role.lambda_role.name
policy = data.aws_iam_policy_document.lambda_permissions.json
tags = local.tags
}

resource "aws_iam_role_policy_attachment" "lambda_policy_attachment" {
resource "aws_iam_role_policy_attachment" "additional_managed_policy_attachment" {
for_each = var.additional_managed_policy_arns

role = aws_iam_role.lambda_role.name
policy_arn = aws_iam_policy.lambda_policy.arn
policy_arn = each.value
}

resource "aws_iam_role_policy" "additional_inline_policy" {
for_each = var.additional_inline_policies

name = "${local.lambda_name}-extra-${each.key}"
role = aws_iam_role.lambda_role.name
policy = each.value
}

resource "aws_lambda_function" "scheduled" {
Expand Down
5 changes: 5 additions & 0 deletions modules/scheduled-lambda/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ output "execution_role_arn" {
value = aws_iam_role.lambda_role.arn
}

output "execution_role_name" {
description = "Name of the Lambda execution role."
value = aws_iam_role.lambda_role.name
}

output "log_group_name" {
description = "CloudWatch log group name for the Lambda function."
value = "/aws/lambda/${aws_lambda_function.scheduled.function_name}"
Expand Down
54 changes: 54 additions & 0 deletions modules/scheduled-lambda/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,57 @@ variable "create_test_url" {
type = bool
default = false
}

# We need the stable keys for the additional policy ARNs because with a list
# of ARNs, we either have problems with foreach on objects that are created
# in the same plan, or we have problems with count/index which makes
# resources index (order) dependent. So arbitrary stable labels are a better
# solution.
variable "additional_managed_policy_arns" {
description = "Additional IAM managed policy ARNs to attach to the Lambda execution role, keyed by stable labels."
type = map(string)
default = {}

validation {
condition = length(var.additional_managed_policy_arns) <= 10
error_message = "additional_managed_policy_arns may contain at most 10 managed policy ARNs."
}

validation {
condition = alltrue([
for label in keys(var.additional_managed_policy_arns) :
can(regex("^[A-Za-z0-9_-]+$", label))
])
error_message = "additional_managed_policy_arns keys must match ^[A-Za-z0-9_-]+$."
}

validation {
condition = alltrue([
for policy_arn in values(var.additional_managed_policy_arns) :
can(regex("^arn:[^:]+:iam::(aws|[0-9]{12}):policy/[A-Za-z0-9+=,.@_/-]+$", trimspace(policy_arn)))
])
error_message = "additional_managed_policy_arns values must be IAM managed policy ARNs."
}
}

variable "additional_inline_policies" {
description = "Additional inline IAM policy JSON documents to attach to the Lambda execution role, keyed by stable labels."
type = map(string)
default = {}

validation {
condition = alltrue([
for label in keys(var.additional_inline_policies) :
can(regex("^[A-Za-z0-9_-]+$", label))
])
error_message = "additional_inline_policies keys must match ^[A-Za-z0-9_-]+$."
}

validation {
condition = alltrue([
for policy_json in values(var.additional_inline_policies) :
can(regex("\\S", policy_json)) && can(jsondecode(policy_json))
])
error_message = "additional_inline_policies values must be non-empty JSON strings."
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an incorrect statement. There's a limit of 10 managed policies, but you can have as many inline as your want (although there is a limit on total length.)

You can add as many inline policies as you want to an IAM user, role, or group.

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-quotas-entity-length

}
5 changes: 5 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ output "scheduled_lambda_role_arn" {
value = module.scheduled_lambda.execution_role_arn
}

output "scheduled_lambda_role_name" {
description = "Name of the scheduled Lambda execution role."
value = module.scheduled_lambda.execution_role_name
}

output "scheduled_lambda_log_group" {
description = "CloudWatch log group name for the scheduled Lambda."
value = module.scheduled_lambda.log_group_name
Expand Down
12 changes: 12 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ variable "create_test_url" {
default = false
}

variable "scheduled_lambda_additional_managed_policy_arns" {
description = "Additional IAM managed policy ARNs to attach to the scheduled Lambda execution role, keyed by stable labels."
type = map(string)
default = {}
}

variable "scheduled_lambda_additional_inline_policies" {
description = "Additional inline IAM policy JSON documents to attach to the scheduled Lambda execution role, keyed by stable labels."
type = map(string)
default = {}
}

variable "tags" {
description = "Tags to apply to created resources."
type = map(string)
Expand Down