Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lambda] feat: allows to use YAML instead of JSON for IAM policy #692

Merged
merged 12 commits into from
Jun 21, 2023
Merged
35 changes: 27 additions & 8 deletions modules/lambda/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,27 @@ components:
# https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html
runtime: python3.9
package_type: Zip # `Zip` or `Image`
policy_json: null

policy_json: |
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListAllBuckets",
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
}
]
}
iam_policy:
statements:
- sid: AllowSQSWorkerWriteAccess
effect: Allow
actions:
- sqs:SendMessage
- sqs:SendMessageBatch
resources:
- arn:aws:sqs:*:111111111111:worker-queue
# Filename example
filename: lambdas/hello-world-python/output.zip # generated by zip variable.
zip:
Expand All @@ -53,7 +72,6 @@ components:
# S3 Source Example
# s3_bucket_name: lambda-source # lambda main.tf calculates the rest of the bucket_name
# s3_key: hello-world-go.zip

```


Expand All @@ -62,7 +80,7 @@ components:

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
| <a name="requirement_archive"></a> [archive](#requirement\_archive) | >= 2.3.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.9.0 |

Expand All @@ -77,6 +95,7 @@ components:

| Name | Source | Version |
|------|--------|---------|
| <a name="module_iam_policy"></a> [iam\_policy](#module\_iam\_policy) | cloudposse/iam-policy/aws | 1.0.1 |
| <a name="module_iam_roles"></a> [iam\_roles](#module\_iam\_roles) | ../account-map/modules/iam-roles | n/a |
| <a name="module_label"></a> [label](#module\_label) | cloudposse/label/null | 0.25.0 |
| <a name="module_lambda"></a> [lambda](#module\_lambda) | cloudposse/lambda-function/aws | 0.4.1 |
Expand All @@ -86,7 +105,6 @@ components:

| Name | Type |
|------|------|
| [aws_iam_policy.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_role_policy_attachment.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [archive_file.lambdazip](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |

Expand All @@ -103,7 +121,7 @@ components:
| <a name="input_cloudwatch_logs_kms_key_arn"></a> [cloudwatch\_logs\_kms\_key\_arn](#input\_cloudwatch\_logs\_kms\_key\_arn) | The ARN of the KMS Key to use when encrypting log data. | `string` | `null` | no |
| <a name="input_cloudwatch_logs_retention_in_days"></a> [cloudwatch\_logs\_retention\_in\_days](#input\_cloudwatch\_logs\_retention\_in\_days) | Specifies the number of days you want to retain log events in the specified log group. Possible values are:<br> 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653, and 0. If you select 0, the events in the<br> log group are always retained and never expire. | `number` | `null` | no |
| <a name="input_context"></a> [context](#input\_context) | Single object for setting entire context at once.<br>See description of individual variables for details.<br>Leave string and numeric variables as `null` to use default value.<br>Individual variable settings (non-null) override settings in context object,<br>except for attributes, tags, and additional\_tag\_map, which are merged. | `any` | <pre>{<br> "additional_tag_map": {},<br> "attributes": [],<br> "delimiter": null,<br> "descriptor_formats": {},<br> "enabled": true,<br> "environment": null,<br> "id_length_limit": null,<br> "label_key_case": null,<br> "label_order": [],<br> "label_value_case": null,<br> "labels_as_tags": [<br> "unset"<br> ],<br> "name": null,<br> "namespace": null,<br> "regex_replace_chars": null,<br> "stage": null,<br> "tags": {},<br> "tenant": null<br>}</pre> | no |
| <a name="input_custom_iam_policy_arns"></a> [custom\_iam\_policy\_arns](#input\_custom\_iam\_policy\_arns) | ARNs of custom policies to be attached to the lambda role | `set(string)` | `[]` | no |
| <a name="input_custom_iam_policy_arns"></a> [custom\_iam\_policy\_arns](#input\_custom\_iam\_policy\_arns) | ARNs of IAM policies to be attached to the Lambda role | `set(string)` | `[]` | no |
| <a name="input_dead_letter_config_target_arn"></a> [dead\_letter\_config\_target\_arn](#input\_dead\_letter\_config\_target\_arn) | ARN of an SNS topic or SQS queue to notify when an invocation fails. If this option is used, the function's IAM role<br> must be granted suitable access to write to the target object, which means allowing either the sns:Publish or<br> sqs:SendMessage action on this ARN, depending on which service is targeted." | `string` | `null` | no |
| <a name="input_delimiter"></a> [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.<br>Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no |
| <a name="input_description"></a> [description](#input\_description) | Description of what the Lambda Function does. | `string` | `null` | no |
Expand All @@ -112,8 +130,9 @@ components:
| <a name="input_environment"></a> [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
| <a name="input_event_source_mappings"></a> [event\_source\_mappings](#input\_event\_source\_mappings) | Creates event source mappings to allow the Lambda function to get events from Kinesis, DynamoDB and SQS. The IAM role<br> of this Lambda function will be enhanced with necessary minimum permissions to get those events. | `any` | `{}` | no |
| <a name="input_filename"></a> [filename](#input\_filename) | The path to the function's deployment package within the local filesystem. If defined, The s3\_-prefixed options and image\_uri cannot be used. | `string` | `null` | no |
| <a name="input_function_name"></a> [function\_name](#input\_function\_name) | Unique name for the Lambda Function. | `string` | n/a | yes |
| <a name="input_function_name"></a> [function\_name](#input\_function\_name) | Unique name for the Lambda Function. | `string` | `null` | no |
| <a name="input_handler"></a> [handler](#input\_handler) | The function entrypoint in your code. | `string` | `null` | no |
| <a name="input_iam_policy"></a> [iam\_policy](#input\_iam\_policy) | IAM policy to attach to the Lambda role, specified as a Terraform object. This can be used with or instead of `var.policy_json`. | <pre>object({<br> policy_id = optional(string, null)<br> version = optional(string, null)<br> statements = list(object({<br> sid = optional(string, null)<br> effect = optional(string, null)<br> actions = optional(list(string), null)<br> not_actions = optional(list(string), null)<br> resources = optional(list(string), null)<br> not_resources = optional(list(string), null)<br> conditions = optional(list(object({<br> test = string<br> variable = string<br> values = list(string)<br> })), [])<br> principals = optional(list(object({<br> type = string<br> identifiers = list(string)<br> })), [])<br> not_principals = optional(list(object({<br> type = string<br> identifiers = list(string)<br> })), [])<br> }))<br> })</pre> | `null` | no |
| <a name="input_iam_policy_description"></a> [iam\_policy\_description](#input\_iam\_policy\_description) | Description of the IAM policy for the Lambda IAM role | `string` | `"Minimum SSM read permissions for Lambda IAM Role"` | no |
| <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br>Set to `0` for unlimited length.<br>Set to `null` for keep the existing setting, which defaults to `0`.<br>Does not affect `id_full`. | `number` | `null` | no |
| <a name="input_ignore_external_function_updates"></a> [ignore\_external\_function\_updates](#input\_ignore\_external\_function\_updates) | Ignore updates to the Lambda Function executed externally to the Terraform lifecycle. Set this to `true` if you're<br> using CodeDeploy, aws CLI or other external tools to update the Lambda Function code." | `bool` | `false` | no |
Expand All @@ -132,7 +151,7 @@ components:
| <a name="input_namespace"></a> [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no |
| <a name="input_package_type"></a> [package\_type](#input\_package\_type) | The Lambda deployment package type. Valid values are `Zip` and `Image`. | `string` | `"Zip"` | no |
| <a name="input_permissions_boundary"></a> [permissions\_boundary](#input\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the role | `string` | `""` | no |
| <a name="input_policy_json"></a> [policy\_json](#input\_policy\_json) | IAM policy to attach to the Lambda IAM role | `string` | `null` | no |
| <a name="input_policy_json"></a> [policy\_json](#input\_policy\_json) | IAM policy to attach to the Lambda role, specified as JSON. This can be used with or instead of `var.iam_policy`. | `string` | `null` | no |
| <a name="input_publish"></a> [publish](#input\_publish) | Whether to publish creation/change as new Lambda Function Version. | `bool` | `false` | no |
| <a name="input_regex_replace_chars"></a> [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.<br>Characters matching the regex will be removed from the ID elements.<br>If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |
| <a name="input_region"></a> [region](#input\_region) | AWS Region | `string` | n/a | yes |
Expand Down
26 changes: 12 additions & 14 deletions modules/lambda/main.tf
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
locals {
enabled = module.this.enabled
iam_policy_enabled = local.enabled && var.policy_json != null
iam_policy_enabled = local.enabled && (try(length(var.iam_policy), 0) > 0 || var.policy_json != null)
s3_bucket_full_name = var.s3_bucket_name != null ? format("%s-%s-%s-%s-%s", module.this.namespace, module.this.tenant, module.this.environment, module.this.stage, var.s3_bucket_name) : null
}



module "label" {
source = "cloudposse/label/null"
version = "0.25.0"
Expand All @@ -15,37 +13,37 @@ module "label" {
context = module.this.context
}

resource "aws_iam_policy" "default" {
count = local.iam_policy_enabled ? 1 : 0
module "iam_policy" {
count = local.iam_policy_enabled ? 1 : 0
source = "cloudposse/iam-policy/aws"
version = "1.0.1"

name = module.label.id
path = "/"
description = format("%s Lambda policy", module.label.id)
policy = var.policy_json
iam_policy_enabled = true
iam_policy = var.iam_policy
iam_source_policy_documents = var.policy_json != null ? [var.policy_json] : []

tags = module.this.tags
context = module.this.context
}

resource "aws_iam_role_policy_attachment" "default" {
count = local.iam_policy_enabled ? 1 : 0

role = module.lambda.role_name
policy_arn = aws_iam_policy.default[0].arn
policy_arn = module.iam_policy[0].policy_arn
}

data "archive_file" "lambdazip" {
count = var.zip.enabled ? 1 : 0
type = "zip"
output_path = "${path.module}/lambdas/${var.zip.output}"

source_dir = "${path.module}/lambdas/${var.zip.input_dir}"
source_dir = "${path.module}/lambdas/${var.zip.input_dir}"
}

module "lambda" {
source = "cloudposse/lambda-function/aws"
version = "0.4.1"

function_name = module.label.id
function_name = coalesce(var.function_name, module.label.id)
gberenice marked this conversation as resolved.
Show resolved Hide resolved
description = var.description
handler = var.handler
lambda_environment = var.lambda_environment
Expand Down
35 changes: 33 additions & 2 deletions modules/lambda/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ variable "region" {
variable "function_name" {
type = string
description = "Unique name for the Lambda Function."
default = null
}

variable "architectures" {
Expand Down Expand Up @@ -246,7 +247,7 @@ variable "vpc_config" {

variable "custom_iam_policy_arns" {
type = set(string)
description = "ARNs of custom policies to be attached to the lambda role"
description = "ARNs of IAM policies to be attached to the Lambda role"
default = []
}

Expand All @@ -268,7 +269,37 @@ variable "iam_policy_description" {

variable "policy_json" {
type = string
description = "IAM policy to attach to the Lambda IAM role"
description = "IAM policy to attach to the Lambda role, specified as JSON. This can be used with or instead of `var.iam_policy`."
default = null
}

variable "iam_policy" {
type = object({
policy_id = optional(string, null)
version = optional(string, null)
statements = list(object({
sid = optional(string, null)
effect = optional(string, null)
actions = optional(list(string), null)
not_actions = optional(list(string), null)
resources = optional(list(string), null)
not_resources = optional(list(string), null)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
not_principals = optional(list(object({
type = string
identifiers = list(string)
})), [])
}))
})
description = "IAM policy to attach to the Lambda role, specified as a Terraform object. This can be used with or instead of `var.policy_json`."
default = null
}

Expand Down
2 changes: 1 addition & 1 deletion modules/lambda/versions.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
terraform {
required_version = ">= 1.0"
required_version = ">= 1.3.0"

required_providers {
aws = {
Expand Down