Skip to content

Commit c2d8e9d

Browse files
authored
Merge pull request #29 from dwhswenson/extra-lambda-role-permissions
Allow extra permissions for lambda role
2 parents 86ce4e7 + e7dff15 commit c2d8e9d

File tree

9 files changed

+156
-18
lines changed

9 files changed

+156
-18
lines changed

examples/basic/main.tf

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,13 @@ locals {
5454
module "lambdacron" {
5555
source = "../.."
5656

57-
aws_region = var.aws_region
58-
lambda_image_uri = local.active_lambda_image_uri
59-
schedule_expression = var.schedule_expression
60-
lambda_name = var.lambda_name
61-
create_test_url = var.create_test_url
57+
aws_region = var.aws_region
58+
lambda_image_uri = local.active_lambda_image_uri
59+
schedule_expression = var.schedule_expression
60+
lambda_name = var.lambda_name
61+
create_test_url = var.create_test_url
62+
scheduled_lambda_additional_managed_policy_arns = var.scheduled_lambda_additional_managed_policy_arns
63+
scheduled_lambda_additional_inline_policies = var.scheduled_lambda_additional_inline_policies
6264

6365
tags = local.common_tags
6466
}

examples/basic/variables.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ variable "create_test_url" {
9494
default = false
9595
}
9696

97+
variable "scheduled_lambda_additional_managed_policy_arns" {
98+
description = "Additional IAM managed policy ARNs to attach to the scheduled Lambda execution role, keyed by stable labels."
99+
type = map(string)
100+
default = {}
101+
}
102+
103+
variable "scheduled_lambda_additional_inline_policies" {
104+
description = "Additional inline IAM policy JSON documents to attach to the scheduled Lambda execution role, keyed by stable labels."
105+
type = map(string)
106+
default = {}
107+
}
108+
97109
variable "email_sender" {
98110
description = "Sender email address for the SES notifier."
99111
type = string

main.tf

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ module "scheduled_lambda" {
2525
schedule_expression = var.schedule_expression
2626
sns_topic_arn = aws_sns_topic.results.arn
2727

28-
lambda_env = var.lambda_env
29-
timeout = var.timeout
30-
memory_size = var.memory_size
31-
lambda_name = var.lambda_name
32-
image_command = var.image_command
33-
create_test_url = var.create_test_url
28+
lambda_env = var.lambda_env
29+
timeout = var.timeout
30+
memory_size = var.memory_size
31+
lambda_name = var.lambda_name
32+
image_command = var.image_command
33+
create_test_url = var.create_test_url
34+
additional_managed_policy_arns = var.scheduled_lambda_additional_managed_policy_arns
35+
additional_inline_policies = var.scheduled_lambda_additional_inline_policies
3436

3537
tags = local.tags
3638
}

modules/scheduled-lambda/README.md

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,52 @@ resource "aws_sns_topic" "results" {
99
name = "cloud-cron-results"
1010
}
1111
12+
resource "aws_iam_policy" "terminate_instance" {
13+
name = "allow-terminate-instance"
14+
15+
policy = jsonencode({
16+
Version = "2012-10-17"
17+
Statement = [
18+
{
19+
Effect = "Allow"
20+
Action = ["ec2:TerminateInstances"]
21+
Resource = ["arn:aws:ec2:us-west-2:123456789012:instance/i-0123456789abcdef0"]
22+
}
23+
]
24+
})
25+
}
26+
27+
data "aws_iam_policy_document" "describe_instances" {
28+
statement {
29+
effect = "Allow"
30+
actions = ["ec2:DescribeInstances"]
31+
resources = ["*"]
32+
}
33+
}
34+
1235
module "scheduled_lambda" {
1336
source = "./modules/scheduled-lambda"
1437
15-
lambda_image_uri = "123456789012.dkr.ecr.us-west-2.amazonaws.com/my-lambda:latest"
16-
schedule_expression = "rate(5 minutes)"
17-
sns_topic_arn = aws_sns_topic.results.arn
38+
lambda_image_uri = "123456789012.dkr.ecr.us-west-2.amazonaws.com/my-lambda:latest"
39+
schedule_expression = "rate(5 minutes)"
40+
sns_topic_arn = aws_sns_topic.results.arn
1841
1942
lambda_env = {
2043
LOG_LEVEL = "info"
2144
}
45+
46+
additional_managed_policy_arns = {
47+
terminate_instance = aws_iam_policy.terminate_instance.arn
48+
}
49+
50+
additional_inline_policies = {
51+
describe_instances = data.aws_iam_policy_document.describe_instances.json
52+
}
2253
}
2354
```
2455

56+
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`.
57+
2558
## Inputs
2659

2760
- `lambda_image_uri` (string): URI of the Lambda container image.
@@ -34,11 +67,14 @@ module "scheduled_lambda" {
3467
- `image_command` (list(string)): Optional override for the container CMD/handler.
3568
- `tags` (map(string)): Tags to apply to created resources.
3669
- `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.
70+
- `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.
71+
- `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.
3772

3873
## Outputs
3974

4075
- `lambda_arn`: ARN of the scheduled Lambda function.
4176
- `execution_role_arn`: ARN of the Lambda execution role.
77+
- `execution_role_name`: Name of the Lambda execution role.
4278
- `log_group_name`: CloudWatch log group name for the Lambda.
4379
- `schedule_rule_name`: Name of the EventBridge schedule rule.
4480
- `test_function_url`: Function URL for temporary testing (null if disabled).

modules/scheduled-lambda/main.tf

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,25 @@ resource "aws_iam_role" "lambda_role" {
4343
tags = local.tags
4444
}
4545

46-
resource "aws_iam_policy" "lambda_policy" {
46+
resource "aws_iam_role_policy" "lambda_permissions" {
4747
name = "${local.lambda_name}-permissions"
48+
role = aws_iam_role.lambda_role.name
4849
policy = data.aws_iam_policy_document.lambda_permissions.json
49-
tags = local.tags
5050
}
5151

52-
resource "aws_iam_role_policy_attachment" "lambda_policy_attachment" {
52+
resource "aws_iam_role_policy_attachment" "additional_managed_policy_attachment" {
53+
for_each = var.additional_managed_policy_arns
54+
5355
role = aws_iam_role.lambda_role.name
54-
policy_arn = aws_iam_policy.lambda_policy.arn
56+
policy_arn = each.value
57+
}
58+
59+
resource "aws_iam_role_policy" "additional_inline_policy" {
60+
for_each = var.additional_inline_policies
61+
62+
name = "${local.lambda_name}-extra-${each.key}"
63+
role = aws_iam_role.lambda_role.name
64+
policy = each.value
5565
}
5666

5767
resource "aws_lambda_function" "scheduled" {

modules/scheduled-lambda/outputs.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ output "execution_role_arn" {
88
value = aws_iam_role.lambda_role.arn
99
}
1010

11+
output "execution_role_name" {
12+
description = "Name of the Lambda execution role."
13+
value = aws_iam_role.lambda_role.name
14+
}
15+
1116
output "log_group_name" {
1217
description = "CloudWatch log group name for the Lambda function."
1318
value = "/aws/lambda/${aws_lambda_function.scheduled.function_name}"

modules/scheduled-lambda/variables.tf

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,57 @@ variable "create_test_url" {
5454
type = bool
5555
default = false
5656
}
57+
58+
# We need the stable keys for the additional policy ARNs because with a list
59+
# of ARNs, we either have problems with foreach on objects that are created
60+
# in the same plan, or we have problems with count/index which makes
61+
# resources index (order) dependent. So arbitrary stable labels are a better
62+
# solution.
63+
variable "additional_managed_policy_arns" {
64+
description = "Additional IAM managed policy ARNs to attach to the Lambda execution role, keyed by stable labels."
65+
type = map(string)
66+
default = {}
67+
68+
validation {
69+
condition = length(var.additional_managed_policy_arns) <= 10
70+
error_message = "additional_managed_policy_arns may contain at most 10 managed policy ARNs."
71+
}
72+
73+
validation {
74+
condition = alltrue([
75+
for label in keys(var.additional_managed_policy_arns) :
76+
can(regex("^[A-Za-z0-9_-]+$", label))
77+
])
78+
error_message = "additional_managed_policy_arns keys must match ^[A-Za-z0-9_-]+$."
79+
}
80+
81+
validation {
82+
condition = alltrue([
83+
for policy_arn in values(var.additional_managed_policy_arns) :
84+
can(regex("^arn:[^:]+:iam::(aws|[0-9]{12}):policy/[A-Za-z0-9+=,.@_/-]+$", trimspace(policy_arn)))
85+
])
86+
error_message = "additional_managed_policy_arns values must be IAM managed policy ARNs."
87+
}
88+
}
89+
90+
variable "additional_inline_policies" {
91+
description = "Additional inline IAM policy JSON documents to attach to the Lambda execution role, keyed by stable labels."
92+
type = map(string)
93+
default = {}
94+
95+
validation {
96+
condition = alltrue([
97+
for label in keys(var.additional_inline_policies) :
98+
can(regex("^[A-Za-z0-9_-]+$", label))
99+
])
100+
error_message = "additional_inline_policies keys must match ^[A-Za-z0-9_-]+$."
101+
}
102+
103+
validation {
104+
condition = alltrue([
105+
for policy_json in values(var.additional_inline_policies) :
106+
can(regex("\\S", policy_json)) && can(jsondecode(policy_json))
107+
])
108+
error_message = "additional_inline_policies values must be non-empty JSON strings."
109+
}
110+
}

outputs.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ output "scheduled_lambda_role_arn" {
1818
value = module.scheduled_lambda.execution_role_arn
1919
}
2020

21+
output "scheduled_lambda_role_name" {
22+
description = "Name of the scheduled Lambda execution role."
23+
value = module.scheduled_lambda.execution_role_name
24+
}
25+
2126
output "scheduled_lambda_log_group" {
2227
description = "CloudWatch log group name for the scheduled Lambda."
2328
value = module.scheduled_lambda.log_group_name

variables.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ variable "create_test_url" {
6767
default = false
6868
}
6969

70+
variable "scheduled_lambda_additional_managed_policy_arns" {
71+
description = "Additional IAM managed policy ARNs to attach to the scheduled Lambda execution role, keyed by stable labels."
72+
type = map(string)
73+
default = {}
74+
}
75+
76+
variable "scheduled_lambda_additional_inline_policies" {
77+
description = "Additional inline IAM policy JSON documents to attach to the scheduled Lambda execution role, keyed by stable labels."
78+
type = map(string)
79+
default = {}
80+
}
81+
7082
variable "tags" {
7183
description = "Tags to apply to created resources."
7284
type = map(string)

0 commit comments

Comments
 (0)