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
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ lambda/
│ │ ├── cleanup_old_version
│ │ ├── merge_iam_policies
│ │ ├── rollback_alias
│ │ ├── rollback_iam_policies
│ │ ├── store_nrn_metadata
│ │ ├── sync_parameters_to_secrets_manager
│ │ ├── update_alias_full
Expand Down
2 changes: 1 addition & 1 deletion lambda/deployment/compute/lambda/modules/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ locals {

# Default tags for Lambda resources
lambda_default_tags = merge(var.lambda_tags, {
ManagedBy = "terraform"
ManagedBy = "custom-scope-role"
Module = local.lambda_module_name
})

Expand Down
4 changes: 2 additions & 2 deletions lambda/deployment/iam/modules/iam.tftest.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ run "applies_tags_to_role" {
}

assert {
condition = aws_iam_role.lambda[0].tags["ManagedBy"] == "terraform"
error_message = "ManagedBy tag should be 'terraform'"
condition = aws_iam_role.lambda[0].tags["ManagedBy"] == "custom-scope-role"
error_message = "ManagedBy tag should be 'custom-scope-role'"
}
}

Expand Down
17 changes: 5 additions & 12 deletions lambda/deployment/iam/modules/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,14 @@ locals {

# Default tags
iam_default_tags = merge(var.iam_resource_tags_json, {
ManagedBy = "terraform"
ManagedBy = "custom-scope-role"
Module = local.iam_module_name
})

# Basic Lambda execution policy ARN
lambda_basic_execution_policy = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"

# VPC access policy ARN
# VPC access policy ARN — kept as managed policy because EC2 network interface
# operations cannot be scoped to specific resources (AWS limitation).
lambda_vpc_access_policy = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"

# Managed policies to attach
iam_managed_policies = var.iam_vpc_enabled ? [
local.lambda_basic_execution_policy,
local.lambda_vpc_access_policy
] : [
local.lambda_basic_execution_policy
]
# Managed policies to attach (only VPC when enabled)
iam_managed_policies = var.iam_vpc_enabled ? [local.lambda_vpc_access_policy] : []
}
37 changes: 35 additions & 2 deletions lambda/deployment/iam/modules/main.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}

# IAM Role for Lambda execution
resource "aws_iam_role" "lambda" {
count = var.iam_create_role ? 1 : 0
Expand All @@ -17,6 +20,8 @@ resource "aws_iam_role" "lambda" {
]
})

permissions_boundary = var.iam_permissions_boundary != "" ? var.iam_permissions_boundary : null

tags = local.iam_default_tags
}

Expand All @@ -37,7 +42,35 @@ resource "aws_iam_role_policy" "custom" {
policy = var.iam_role_policies[count.index].policy
}

# ECR pull permissions — always added when creating the role.
# CloudWatch Logs — scoped to the Lambda's own log group.
# Replaces the AWSLambdaBasicExecutionRole managed policy which grants logs:* on Resource: *.
resource "aws_iam_role_policy" "cloudwatch_logs" {
count = var.iam_create_role ? 1 : 0

name = "cloudwatch-logs"
role = aws_iam_role.lambda[0].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = "logs:CreateLogGroup"
Resource = "arn:aws:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/${var.iam_function_name}"
},
{
Effect = "Allow"
Action = [
"logs:CreateLogStream",
"logs:PutLogEvents"
]
Resource = "arn:aws:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/${var.iam_function_name}:*"
}
]
})
}

# ECR pull permissions — scoped to repositories in the same account.
# ecr:GetAuthorizationToken requires Resource: * (AWS limitation).
# The placeholder Lambda always uses a container image regardless of scope package type,
# so ECR access is required from the first deployment onward.
resource "aws_iam_role_policy" "ecr" {
Expand All @@ -54,7 +87,7 @@ resource "aws_iam_role_policy" "ecr" {
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer"
]
Resource = "*"
Resource = "arn:aws:ecr:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:repository/*"
},
{
Effect = "Allow"
Expand Down
11 changes: 11 additions & 0 deletions lambda/deployment/iam/modules/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,14 @@ variable "iam_scope_id" {
type = string
default = ""
}

variable "iam_permissions_boundary" {
description = "ARN of the IAM permissions boundary to attach to the Lambda execution role (empty to disable)"
type = string
default = ""
}

variable "iam_function_name" {
description = "Lambda function name — used to scope CloudWatch Logs permissions to /aws/lambda/{function_name}"
type = string
}
3 changes: 2 additions & 1 deletion lambda/deployment/iam/setup
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ log debug " 📋 vpc_enabled=$vpc_enabled"
TOFU_VARIABLES=$(echo "$TOFU_VARIABLES" | jq \
--arg role_name "$iam_role_name" \
--arg scope_id "$SCOPE_ID" \
--arg function_name "$LAMBDA_FUNCTION_NAME" \
--arg duration "$propagation_duration" \
--argjson vpc_enabled "$vpc_enabled" \
'. + {iam_create_role: true, iam_role_name: $role_name, iam_scope_id: $scope_id, iam_propagation_duration: $duration, iam_vpc_enabled: $vpc_enabled}')
'. + {iam_create_role: true, iam_role_name: $role_name, iam_scope_id: $scope_id, iam_function_name: $function_name, iam_propagation_duration: $duration, iam_vpc_enabled: $vpc_enabled}')

log info "✨ IAM configured"
echo ""
Expand Down
4 changes: 2 additions & 2 deletions lambda/deployment/networking/alb/modules/alb.tftest.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ run "applies_tags_to_target_group" {
}

assert {
condition = aws_lb_target_group.lambda.tags["ManagedBy"] == "terraform"
error_message = "ManagedBy tag should be 'terraform'"
condition = aws_lb_target_group.lambda.tags["ManagedBy"] == "custom-scope-role"
error_message = "ManagedBy tag should be 'custom-scope-role'"
}
}

Expand Down
2 changes: 1 addition & 1 deletion lambda/deployment/networking/alb/modules/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ locals {

# Default tags
alb_default_tags = merge(var.alb_resource_tags_json, {
ManagedBy = "terraform"
ManagedBy = "custom-scope-role"
Module = local.alb_module_name
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ run "applies_tags_to_api" {
}

assert {
condition = aws_apigatewayv2_api.main.tags["ManagedBy"] == "terraform"
error_message = "ManagedBy tag should be 'terraform'"
condition = aws_apigatewayv2_api.main.tags["ManagedBy"] == "custom-scope-role"
error_message = "ManagedBy tag should be 'custom-scope-role'"
}
}

Expand Down
2 changes: 1 addition & 1 deletion lambda/deployment/networking/api_gateway/modules/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ locals {

# Default tags
api_gateway_default_tags = merge(var.api_gateway_resource_tags_json, {
ManagedBy = "terraform"
ManagedBy = "custom-scope-role"
Module = local.api_gateway_module_name
})

Expand Down
27 changes: 3 additions & 24 deletions lambda/deployment/scripts/merge_iam_policies
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,12 @@ if [ -z "${DEPLOYMENT_ID:-}" ]; then
return 1
fi

if [ -z "${SCOPE_NRN:-}" ]; then
echo "❌ SCOPE_NRN is required" >&2
echo "💡 Possible causes:" >&2
echo " - Scope context not available in the environment" >&2
echo " - NRN not passed from the deployment pipeline" >&2
echo "🔧 How to fix:" >&2
echo " - Verify SCOPE_NRN is exported before this script runs" >&2
echo " - Check the deployment agent configuration" >&2
return 1
fi

log debug " ✅ role_name=$LAMBDA_ROLE_NAME"
log debug " ✅ deployment_id=$DEPLOYMENT_ID"

deployment_nrn="${SCOPE_NRN}:deployment=${DEPLOYMENT_ID}"
log info " 📡 Reading deployment policies from NRN=$deployment_nrn..."

nrn_output=$(np nrn read --nrn "$deployment_nrn" --namespace aws --format json 2>&1 || echo "{}")
policies=$(echo "$nrn_output" | jq -r '.AWS_LAMBDA_DEDICATED_ROLE_POLICIES // "[]"')
# Read policies from scope-configurations provider
log info " 📡 Reading deployment policies from scope-configurations provider..."
policies=$(echo "$CONTEXT" | jq -r '.providers["scope-configurations"].lambda.role_policies // "[]"')

if [ "$policies" = "[]" ] || [ "$policies" = "null" ]; then
log info " ⏭️ No deployment-specific policies to merge"
Expand Down Expand Up @@ -87,13 +74,5 @@ for i in $(seq 0 $((policy_count - 1))); do
log debug " ✅ Policy $full_policy_name attached successfully"
done

echo ""
log info " 📝 Storing policies in deployment NRN=$deployment_nrn..."
np nrn write \
--nrn "$deployment_nrn" \
--namespace aws \
--body "{\"AWS_LAMBDA_MERGED_POLICIES\": $policies}" \
--format json >/dev/null 2>&1 || true

echo ""
log info "✨ IAM policies merged successfully for role=$LAMBDA_ROLE_NAME deployment=$DEPLOYMENT_ID"
2 changes: 0 additions & 2 deletions lambda/deployment/scripts/rollback_alias
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ if [ -z "$previous_version" ] || [ "$previous_version" = "null" ]; then
echo "💡 Possible causes:" >&2
echo " - This is the first deployment (no active deployment exists)" >&2
echo " - LAMBDA_BLUE_VERSION was not exported from build_context" >&2
echo " - NRN has no version stored for active deployment=$BLUE_DEPLOYMENT_ID" >&2
echo "🔧 How to fix:" >&2
echo " - Verify NRN: np nrn read --nrn $SCOPE_NRN --ids \"lambda.deployment_version_${BLUE_DEPLOYMENT_ID//-/_}\" --format json" >&2
echo " - Manually set the alias version if the previous version is known" >&2
return 1
fi
Expand Down
73 changes: 0 additions & 73 deletions lambda/deployment/scripts/rollback_iam_policies

This file was deleted.

Loading