Skip to content

Fix OIDC trust + permissions boundary for password-set role#58

Merged
Alexanderamiri merged 1 commit into
mainfrom
fix/password-set-boundary
Mar 13, 2026
Merged

Fix OIDC trust + permissions boundary for password-set role#58
Alexanderamiri merged 1 commit into
mainfrom
fix/password-set-boundary

Conversation

@Alexanderamiri
Copy link
Copy Markdown
Member

Summary

  • OIDC trust policy: apply job uses environment: production, which makes GitHub send repo:javaBin/platform:environment:production as the sub claim instead of repo:javaBin/platform:ref:refs/heads/main. Added both formats.
  • Permissions boundary: javabin-password-set role needs permissions_boundary — the developer boundary blocks creating roles without it.
  • Reverts v5 pin: Pin configure-aws-credentials to v5 for ci-infra role #57 pinned credentials to v5, but v5 vs v6 wasn't the issue — it was the sub claim mismatch.

Test plan

  • Apply succeeds — creates password-set Lambda + role + function URL

Two issues blocking apply:
1. ci-infra OIDC trust only matched ref-based sub claims, but the apply
   job uses `environment: production` which sends environment-based claims.
   Added both formats to the trust condition.
2. password-set IAM role was missing permissions_boundary, which the
   developer boundary requires for all new roles created via CI.

Also reverts v5 pin from #57 since that wasn't the root cause.
@Alexanderamiri Alexanderamiri enabled auto-merge (squash) March 13, 2026 22:51
@github-actions
Copy link
Copy Markdown

Terraform Plan

Changes detected — review required.

Plan output
module.lambdas.data.archive_file.compliance_reporter: Reading...
module.lambdas.data.archive_file.apply_gate: Reading...
module.lambdas.data.archive_file.password_set: Reading...
module.lambdas.data.archive_file.override_cleanup: Reading...
module.lambdas.data.archive_file.cost_report: Reading...
module.lambdas.data.archive_file.daily_cost_check: Reading...
module.lambdas.data.archive_file.apply_gate: Read complete after 0s [id=064e560a455ec8b2a30253cd815a820ad002376f]
module.lambdas.data.archive_file.compliance_reporter: Read complete after 0s [id=323449bf04f46a46a9d9c440212010f551146129]
module.lambdas.data.archive_file.password_set: Read complete after 0s [id=e8642f74f5c1054e7105a8b6834ee7508b1f30c1]
module.lambdas.data.archive_file.override_cleanup: Read complete after 0s [id=08e23a8ca152c50d8321f7b9f15d3ebbdc97849d]
module.lambdas.data.archive_file.team_provisioner: Reading...
module.lambdas.data.archive_file.slack_alert: Reading...
module.lambdas.data.archive_file.cost_report: Read complete after 0s [id=9844b77d6a3a4efa27510589543ad38c835cc662]
module.lambdas.data.archive_file.daily_cost_check: Read complete after 0s [id=da9c5f6e85719534eb3d93b02eca8a30fbbfeb34]
module.lambdas.data.archive_file.team_provisioner: Read complete after 0s [id=2c3923c60cf0a4be10a515c74f37b631cb2be676]
module.lambdas.data.archive_file.slack_alert: Read complete after 0s [id=4e0e1617392370ce9f1308884a7e0d9636829292]
module.lambdas.aws_cloudwatch_event_rule.override_cleanup_schedule: Refreshing state... [id=javabin-override-cleanup-schedule]
module.lambdas.aws_iam_role.apply_gate: Refreshing state... [id=javabin-apply-gate]
module.networking.aws_eip.nat: Refreshing state... [id=eipalloc-0764f0a1a3c80dce1]
module.networking.data.aws_availability_zones.available: Reading...
module.identity.aws_cognito_user_pool.internal: Refreshing state... [id=eu-central-1_Icikv3dtD]
module.ingress.aws_acm_certificate.wildcard: Refreshing state... [id=arn:aws:acm:eu-central-1:553637109631:certificate/9b79f56a-3719-4c62-8970-6f08985a7e5b]
module.monitoring.aws_cloudwatch_event_rule.console_login: Refreshing state... [id=javabin-console-login]
module.monitoring.aws_guardduty_detector.main: Refreshing state... [id=f1df02cf279e4b5986ce1e9bcb3af9c5]
module.identity.aws_cognito_user_pool.external: Refreshing state... [id=eu-central-1_gdFOsE4EM]
module.ingress.data.aws_route53_zone.main: Reading...
module.lambdas.aws_cloudwatch_event_rule.compliance_reporter_trigger: Refreshing state... [id=javabin-compliance-reporter-trigger]
module.ingress.data.aws_route53_zone.main: Read complete after 0s [id=Z09335963LMV0Z5QB9L45]
module.iam.data.aws_iam_openid_connect_provider.github: Reading...
module.iam.data.aws_iam_openid_connect_provider.github: Read complete after 0s [id=arn:aws:iam::553637109631:oidc-provider/token.actions.githubusercontent.com]
module.lambdas.aws_cloudwatch_event_rule.securityhub_summary_schedule: Refreshing state... [id=javabin-securityhub-summary-schedule]
module.networking.data.aws_availability_zones.available: Read complete after 0s [id=eu-central-1]
module.lambdas.aws_iam_role.compliance_reporter: Refreshing state... [id=javabin-compliance-reporter]
module.lambdas.aws_iam_role.cost_report: Refreshing state... [id=javabin-cost-report]
module.lambdas.aws_iam_role.override_cleanup: Refreshing state... [id=javabin-override-cleanup]
module.lambdas.aws_iam_role.team_provisioner: Refreshing state... [id=javabin-team-provisioner]
module.monitoring.aws_sns_topic.security: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-security]
module.lambdas.aws_iam_role.slack_alert: Refreshing state... [id=javabin-slack-alert]
module.monitoring.aws_sns_topic.alerts: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-alerts]
module.monitoring.aws_dynamodb_table.alert_dedup: Refreshing state... [id=javabin-alert-dedup]
module.monitoring.aws_cloudwatch_event_rule.iam_changes: Refreshing state... [id=javabin-iam-changes]
module.lambdas.aws_cloudwatch_event_rule.daily_cost_check_schedule: Refreshing state... [id=javabin-daily-cost-check-schedule]
module.monitoring.aws_cloudwatch_event_rule.resource_modification: Refreshing state... [id=javabin-resource-modification]
module.monitoring.aws_cloudwatch_event_rule.guardduty_findings: Refreshing state... [id=javabin-guardduty-findings]
module.monitoring.aws_s3_bucket.config_logs: Refreshing state... [id=javabin-config-553637109631]
module.monitoring.aws_ce_anomaly_monitor.main: Refreshing state... [id=arn:aws:ce::553637109631:anomalymonitor/3609b3f1-c834-444e-a218-02ac6da1cb4d]
module.lambdas.aws_iam_role.daily_cost_check: Refreshing state... [id=javabin-daily-cost-check]
module.compute.aws_ecs_cluster.main: Refreshing state... [id=arn:aws:ecs:eu-central-1:553637109631:cluster/javabin-platform]
module.lambdas.aws_cloudwatch_event_rule.cost_report_schedule: Refreshing state... [id=javabin-cost-report-schedule]
module.monitoring.aws_securityhub_account.main: Refreshing state... [id=553637109631]
module.monitoring.aws_cloudwatch_event_rule.config_compliance: Refreshing state... [id=javabin-config-compliance-change]
module.monitoring.aws_cloudwatch_event_rule.resource_creation: Refreshing state... [id=javabin-resource-creation]
module.compute.aws_ecr_repository.ci["jvm"]: Refreshing state... [id=javabin-ci-jvm]
module.networking.aws_vpc.main: Refreshing state... [id=vpc-0cd3502de2527a310]
module.compute.aws_ecr_repository.ci["platform"]: Refreshing state... [id=javabin-ci-platform]
module.compute.aws_ecr_repository.ci["ts"]: Refreshing state... [id=javabin-ci-ts]
module.monitoring.aws_iam_role.config_role: Refreshing state... [id=javabin-config-role]
module.iam.aws_iam_role.ecs_execution: Refreshing state... [id=javabin-ecs-execution]
module.monitoring.aws_cloudwatch_event_rule.securityhub_findings: Refreshing state... [id=javabin-securityhub-findings]
module.iam.aws_iam_policy.developer_boundary: Refreshing state... [id=arn:aws:iam::553637109631:policy/javabin-developer-boundary]
module.lambdas.aws_iam_role_policy.apply_gate: Refreshing state... [id=javabin-apply-gate:javabin-apply-gate]
module.lambdas.aws_iam_role_policy_attachment.apply_gate_logs: Refreshing state... [id=javabin-apply-gate-20260310000556680800000001]
module.lambdas.aws_lambda_function.apply_gate: Refreshing state... [id=javabin-apply-gate]
module.monitoring.aws_guardduty_detector_feature.runtime_monitoring: Refreshing state... [id=f1df02cf279e4b5986ce1e9bcb3af9c5/RUNTIME_MONITORING]
module.ingress.aws_route53_record.acm_validation["*.javazone.no"]: Refreshing state... [id=Z09335963LMV0Z5QB9L45__b68529ef50ff68d6cf320ff0e9c5c80a.javazone.no._CNAME]
module.lambdas.aws_iam_role_policy_attachment.compliance_reporter_logs: Refreshing state... [id=javabin-compliance-reporter-20260307162857302300000005]
module.lambdas.aws_lambda_function.compliance_reporter: Refreshing state... [id=javabin-compliance-reporter]
module.lambdas.aws_iam_role_policy.compliance_reporter: Refreshing state... [id=javabin-compliance-reporter:javabin-compliance-reporter]
module.identity.aws_cognito_user_pool_domain.internal: Refreshing state... [id=javabin-internal]
module.lambdas.aws_iam_role_policy.cost_report: Refreshing state... [id=javabin-cost-report:javabin-cost-report]
module.lambdas.aws_lambda_function.cost_report: Refreshing state... [id=javabin-cost-report]
module.lambdas.aws_iam_role_policy_attachment.cost_report_logs: Refreshing state... [id=javabin-cost-report-20260307162857662100000006]
module.lambdas.aws_iam_role_policy.override_cleanup: Refreshing state... [id=javabin-override-cleanup:javabin-override-cleanup]
module.lambdas.aws_iam_role_policy_attachment.override_cleanup_logs: Refreshing state... [id=javabin-override-cleanup-20260307162858005200000007]
module.lambdas.aws_lambda_function.override_cleanup: Refreshing state... [id=javabin-override-cleanup]
module.lambdas.aws_iam_role_policy_attachment.team_provisioner_logs: Refreshing state... [id=javabin-team-provisioner-20260307162856464600000003]
module.lambdas.aws_iam_role_policy_attachment.slack_alert_logs: Refreshing state... [id=javabin-slack-alert-20260307162858376500000008]
module.lambdas.aws_lambda_function.daily_cost_check: Refreshing state... [id=javabin-daily-cost-check]
module.lambdas.aws_iam_role_policy.daily_cost_check: Refreshing state... [id=javabin-daily-cost-check:javabin-daily-cost-check]
module.lambdas.aws_iam_role_policy_attachment.daily_cost_check_logs: Refreshing state... [id=javabin-daily-cost-check-20260307162856210400000002]
module.monitoring.aws_cloudwatch_event_target.iam_changes_sns: Refreshing state... [id=javabin-iam-changes-send-to-security-sns]
module.monitoring.aws_sns_topic_policy.security: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-security]
module.monitoring.aws_cloudwatch_event_target.resource_modification_sns: Refreshing state... [id=javabin-resource-modification-send-to-security-sns]
module.monitoring.aws_cloudwatch_event_target.console_login_sns: Refreshing state... [id=javabin-console-login-send-to-security-sns]
module.monitoring.aws_cloudwatch_event_target.guardduty_findings_sns: Refreshing state... [id=javabin-guardduty-findings-send-to-security-sns]
module.monitoring.aws_cloudwatch_event_target.config_compliance_sns: Refreshing state... [id=javabin-config-compliance-change-send-to-security-sns]
module.monitoring.aws_cloudwatch_event_target.resource_creation_sns: Refreshing state... [id=javabin-resource-creation-send-to-security-sns]
module.monitoring.aws_sns_topic_policy.alerts: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-alerts]
module.monitoring.aws_ce_anomaly_subscription.alerts: Refreshing state... [id=arn:aws:ce::553637109631:anomalysubscription/f6b079c9-5174-43b7-85f3-dde533995482]
module.monitoring.aws_iam_role_policy_attachment.config_role: Refreshing state... [id=javabin-config-role-20260307162900971300000009]
module.monitoring.aws_config_configuration_recorder.main: Refreshing state... [id=javabin-recorder]
module.monitoring.aws_securityhub_standards_subscription.aws_foundational: Refreshing state... [id=arn:aws:securityhub:eu-central-1:553637109631:subscription/aws-foundational-security-best-practices/v/1.0.0]
module.compute.aws_ecs_cluster_capacity_providers.main: Refreshing state... [id=javabin-platform]
module.iam.aws_iam_role_policy_attachment.ecs_execution_base: Refreshing state... [id=javabin-ecs-execution-20260307162856804400000004]
module.iam.aws_iam_role_policy.ecs_execution_secrets: Refreshing state... [id=javabin-ecs-execution:secrets-read]
module.iam.aws_iam_role.ci_infra_plan: Refreshing state... [id=javabin-ci-infra-plan]
module.iam.aws_iam_role.ci_registry: Refreshing state... [id=javabin-ci-registry]
module.iam.aws_iam_role.ci_apply_gate: Refreshing state... [id=javabin-ci-apply-gate]
module.iam.aws_iam_role.ci_deploy["platform-test-app"]: Refreshing state... [id=javabin-ci-deploy-platform-test-app]
module.iam.aws_iam_role.ci_infra: Refreshing state... [id=javabin-ci-infra]
module.iam.aws_iam_role.ci_override_approver: Refreshing state... [id=javabin-ci-override-approver]
module.monitoring.aws_cloudwatch_event_target.securityhub_findings_sns: Refreshing state... [id=javabin-securityhub-findings-send-to-security-sns]
module.ingress.aws_acm_certificate_validation.wildcard: Refreshing state... [id=2026-03-07 16:29:14.551 +0000 UTC]
module.compute.aws_ecr_lifecycle_policy.ci["jvm"]: Refreshing state... [id=javabin-ci-jvm]
module.compute.aws_ecr_lifecycle_policy.ci["platform"]: Refreshing state... [id=javabin-ci-platform]
module.compute.aws_ecr_lifecycle_policy.ci["ts"]: Refreshing state... [id=javabin-ci-ts]
module.lambdas.aws_lambda_permission.cost_report_schedule: Refreshing state... [id=AllowEventBridge]
module.iam.aws_iam_role.ci_app["platform-test-app"]: Refreshing state... [id=javabin-ci-app-platform-test-app]
module.lambdas.aws_cloudwatch_event_target.cost_report: Refreshing state... [id=javabin-cost-report-schedule-invoke-cost-report]
module.lambdas.aws_cloudwatch_event_target.compliance_reporter: Refreshing state... [id=javabin-compliance-reporter-trigger-invoke-compliance-reporter]
module.lambdas.aws_lambda_permission.compliance_reporter_eventbridge: Refreshing state... [id=AllowEventBridge]
module.lambdas.aws_lambda_permission.override_cleanup_schedule: Refreshing state... [id=AllowEventBridge]
module.lambdas.aws_cloudwatch_event_target.override_cleanup: Refreshing state... [id=javabin-override-cleanup-schedule-invoke-override-cleanup]
module.networking.aws_subnet.public_b: Refreshing state... [id=subnet-0eb818326ee94a266]
module.networking.aws_subnet.private_a: Refreshing state... [id=subnet-0329ad20dc025c693]
module.networking.aws_subnet.private_b: Refreshing state... [id=subnet-09ee21336f809f3c9]
module.networking.aws_internet_gateway.main: Refreshing state... [id=igw-07b193bea823a7f69]
module.networking.aws_security_group.ecs_tasks: Refreshing state... [id=sg-0df9a0a3a22548c62]
module.networking.aws_subnet.public_a: Refreshing state... [id=subnet-0f6bfec917146b856]
module.networking.aws_security_group.alb: Refreshing state... [id=sg-061000c0fa68a41b7]
module.lambdas.aws_lambda_permission.daily_cost_check_schedule: Refreshing state... [id=AllowEventBridge]
module.lambdas.aws_cloudwatch_event_target.daily_cost_check: Refreshing state... [id=javabin-daily-cost-check-schedule-invoke-daily-cost-check]
module.iam.aws_iam_role_policy.ci_registry: Refreshing state... [id=javabin-ci-registry:registry-operations]
module.iam.aws_iam_role_policy.ci_infra_plan_extras: Refreshing state... [id=javabin-ci-infra-plan:plan-specific-writes]
module.iam.aws_iam_role_policy_attachment.ci_infra_plan_readonly: Refreshing state... [id=javabin-ci-infra-plan-20260312151931668600000001]
module.lambdas.aws_iam_role_policy.team_provisioner: Refreshing state... [id=javabin-team-provisioner:javabin-team-provisioner]
module.iam.aws_iam_role_policy.ci_apply_gate: Refreshing state... [id=javabin-ci-apply-gate:invoke-gate-and-read-plans]
module.lambdas.aws_iam_role_policy.slack_alert: Refreshing state... [id=javabin-slack-alert:javabin-slack-alert]
module.lambdas.aws_lambda_function.team_provisioner: Refreshing state... [id=javabin-team-provisioner]
module.lambdas.aws_lambda_function.slack_alert: Refreshing state... [id=javabin-slack-alert]
module.lambdas.aws_lambda_function.securityhub_summary: Refreshing state... [id=javabin-securityhub-summary]
module.iam.aws_iam_role_policy.ci_infra_allow: Refreshing state... [id=javabin-ci-infra:infra-management]
module.iam.aws_iam_role_policy.ci_infra_deny: Refreshing state... [id=javabin-ci-infra:deny-dangerous-operations]
module.iam.aws_iam_role_policy.ci_override_approver: Refreshing state... [id=javabin-ci-override-approver:invoke-apply-gate]
module.monitoring.aws_s3_bucket_public_access_block.config_logs: Refreshing state... [id=javabin-config-553637109631]
module.monitoring.aws_s3_bucket_policy.config_logs: Refreshing state... [id=javabin-config-553637109631]
module.monitoring.aws_s3_bucket_server_side_encryption_configuration.config_logs: Refreshing state... [id=javabin-config-553637109631]
module.iam.aws_iam_role_policy.ci_deploy_ecr["platform-test-app"]: Refreshing state... [id=javabin-ci-deploy-platform-test-app:ecr-push]
module.iam.aws_iam_role_policy.ci_deploy_ecs["platform-test-app"]: Refreshing state... [id=javabin-ci-deploy-platform-test-app:ecs-deploy]
module.iam.aws_iam_role_policy.ci_deploy_logs["platform-test-app"]: Refreshing state... [id=javabin-ci-deploy-platform-test-app:cloudwatch-logs]
module.iam.aws_iam_role_policy.ci_deploy_ssm["platform-test-app"]: Refreshing state... [id=javabin-ci-deploy-platform-test-app:ssm-read-overrides]
module.monitoring.aws_config_delivery_channel.main: Refreshing state... [id=javabin-config-channel]
module.monitoring.aws_config_config_rule.required_tags: Refreshing state... [id=javabin-required-tags]
module.iam.aws_iam_role_policy.ci_app_allow["platform-test-app"]: Refreshing state... [id=javabin-ci-app-platform-test-app:app-management]
module.iam.aws_iam_role_policy.ci_app_deny["platform-test-app"]: Refreshing state... [id=javabin-ci-app-platform-test-app:deny-platform-operations]
module.networking.aws_route_table.public: Refreshing state... [id=rtb-01c9642f019d36b1f]
module.networking.aws_vpc_security_group_egress_rule.ecs_all: Refreshing state... [id=sgr-0266cfa56e8feab14]
module.networking.aws_nat_gateway.main: Refreshing state... [id=nat-0e9cc9e27cc6598db]
module.networking.aws_vpc_security_group_ingress_rule.ecs_from_alb: Refreshing state... [id=sgr-064d01025000f601e]
module.networking.aws_vpc_security_group_egress_rule.alb_all: Refreshing state... [id=sgr-021faee81305c6e28]
module.networking.aws_vpc_security_group_ingress_rule.alb_http: Refreshing state... [id=sgr-07c58f16ef7496031]
module.networking.aws_vpc_security_group_ingress_rule.alb_https: Refreshing state... [id=sgr-00b490b07c35193b7]
module.monitoring.aws_config_configuration_recorder_status.main: Refreshing state... [id=javabin-recorder]
module.lambdas.aws_lambda_permission.securityhub_summary_schedule: Refreshing state... [id=AllowEventBridge]
module.lambdas.aws_cloudwatch_event_target.securityhub_summary: Refreshing state... [id=javabin-securityhub-summary-schedule-invoke-securityhub-summary]
module.ingress.aws_lb.main: Refreshing state... [id=arn:aws:elasticloadbalancing:eu-central-1:553637109631:loadbalancer/app/javabin-platform-alb/bec1dd43ab8341b9]
module.networking.aws_route_table_association.public_a: Refreshing state... [id=rtbassoc-07ff2e0bfa1578067]
module.networking.aws_route_table.private: Refreshing state... [id=rtb-0b0b4c643592a7db0]
module.networking.aws_route_table_association.public_b: Refreshing state... [id=rtbassoc-0186c3a7f0279e344]
module.lambdas.aws_lambda_permission.slack_alert_alerts: Refreshing state... [id=AllowSNSAlerts]
module.lambdas.aws_sns_topic_subscription.slack_alert_alerts: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-alerts:380384a2-0cac-48c9-b2d9-2a0aae6968cd]
module.lambdas.aws_lambda_permission.slack_alert_security: Refreshing state... [id=AllowSNSSecurity]
module.lambdas.aws_sns_topic_subscription.slack_alert_security: Refreshing state... [id=arn:aws:sns:eu-central-1:553637109631:javabin-security:0bda8a22-7a50-4a9d-9285-6b1fc1f75376]
module.networking.aws_route_table_association.private_a: Refreshing state... [id=rtbassoc-0b9248495de9f7316]
module.networking.aws_route_table_association.private_b: Refreshing state... [id=rtbassoc-005259f36758e089e]
module.ingress.aws_lb_listener.https: Refreshing state... [id=arn:aws:elasticloadbalancing:eu-central-1:553637109631:listener/app/javabin-platform-alb/bec1dd43ab8341b9/500c9c2b4186bf45]
module.ingress.aws_lb_listener.http_redirect: Refreshing state... [id=arn:aws:elasticloadbalancing:eu-central-1:553637109631:listener/app/javabin-platform-alb/bec1dd43ab8341b9/1d92e19ae75aa59b]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.lambdas.aws_iam_role.password_set will be created
  + resource "aws_iam_role" "password_set" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "lambda.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-password-set"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-developer-boundary"
      + tags_all              = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "project"     = "javabin"
          + "team"        = "javabin"
        }
      + unique_id             = (known after apply)
    }

  # module.lambdas.aws_iam_role_policy.password_set will be created
  + resource "aws_iam_role_policy" "password_set" {
      + id          = (known after apply)
      + name        = "javabin-password-set"
      + name_prefix = (known after apply)
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = "ssm:GetParameter"
                      + Effect   = "Allow"
                      + Resource = [
                          + "arn:aws:ssm:eu-central-1:553637109631:parameter/javabin/platform/*",
                        ]
                      + Sid      = "SSMRead"
                    },
                  + {
                      + Action   = [
                          + "dynamodb:GetItem",
                          + "dynamodb:PutItem",
                        ]
                      + Effect   = "Allow"
                      + Resource = "arn:aws:dynamodb:eu-central-1:553637109631:table/javabin-alert-dedup"
                      + Sid      = "DynamoDBDedup"
                    },
                  + {
                      + Action   = "lambda:InvokeFunction"
                      + Effect   = "Allow"
                      + Resource = "arn:aws:lambda:eu-central-1:553637109631:function:javabin-team-provisioner"
                      + Sid      = "InvokeTeamProvisioner"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role        = (known after apply)
    }

  # module.lambdas.aws_iam_role_policy_attachment.password_set_logs will be created
  + resource "aws_iam_role_policy_attachment" "password_set_logs" {
      + id         = (known after apply)
      + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
      + role       = "javabin-password-set"
    }

  # module.lambdas.aws_lambda_function.password_set will be created
  + resource "aws_lambda_function" "password_set" {
      + architectures                  = (known after apply)
      + arn                            = (known after apply)
      + code_sha256                    = (known after apply)
      + filename                       = "lambdas/builds/password_set.zip"
      + function_name                  = "javabin-password-set"
      + handler                        = "handler.handler"
      + id                             = (known after apply)
      + invoke_arn                     = (known after apply)
      + last_modified                  = (known after apply)
      + memory_size                    = 128
      + package_type                   = "Zip"
      + publish                        = false
      + qualified_arn                  = (known after apply)
      + qualified_invoke_arn           = (known after apply)
      + reserved_concurrent_executions = -1
      + role                           = (known after apply)
      + runtime                        = "python3.12"
      + signing_job_arn                = (known after apply)
      + signing_profile_version_arn    = (known after apply)
      + skip_destroy                   = false
      + source_code_hash               = "2/h0Ae5IHdTiObH7e8ZKRfT9tc8W/v9Z9cqwRpCwiDg="
      + source_code_size               = (known after apply)
      + tags_all                       = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "project"     = "javabin"
          + "team"        = "javabin"
        }
      + timeout                        = 30
      + version                        = (known after apply)

      + environment {
          + variables = {
              + "DEDUP_TABLE_NAME"          = "javabin-alert-dedup"
              + "SIGNING_KEY_PARAM"         = "/javabin/platform/password-token-signing-key"
              + "TEAM_PROVISIONER_FUNCTION" = "javabin-team-provisioner"
            }
        }
    }

  # module.lambdas.aws_lambda_function_url.password_set will be created
  + resource "aws_lambda_function_url" "password_set" {
      + authorization_type = "NONE"
      + function_arn       = (known after apply)
      + function_name      = "javabin-password-set"
      + function_url       = (known after apply)
      + id                 = (known after apply)
      + invoke_mode        = "BUFFERED"
      + url_id             = (known after apply)
    }

  # module.lambdas.aws_ssm_parameter.password_set_function_url will be created
  + resource "aws_ssm_parameter" "password_set_function_url" {
      + arn            = (known after apply)
      + data_type      = (known after apply)
      + has_value_wo   = (known after apply)
      + id             = (known after apply)
      + insecure_value = (known after apply)
      + key_id         = (known after apply)
      + name           = "/javabin/platform/password-set-function-url"
      + tags_all       = {
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "project"     = "javabin"
          + "team"        = "javabin"
        }
      + tier           = (known after apply)
      + type           = "String"
      + value          = (sensitive value)
      + version        = (known after apply)
    }

Plan: 6 to add, 0 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

@github-actions
Copy link
Copy Markdown

LLM Plan Review

Risk: 🟢 LOW

Adding a new password-set Lambda function with appropriate IAM permissions, permissions boundary, and secure configuration.

  • [routine] New Lambda function (password_set) being created with standard Python 3.12 runtime, 128MB memory, and 30s timeout - typical configuration for a utility function
  • [routine] IAM role includes permissions boundary (javabin-developer-boundary) which restricts maximum permissions - good security practice
  • [routine] Lambda has minimal, scoped IAM permissions: SSM parameter read, DynamoDB dedup table access, and ability to invoke team-provisioner function - follows least privilege principle
  • 🔒 [security] Lambda function URL created with authorization_type=NONE (public access), but this appears intentional for a password-set endpoint. Ensure this is documented and monitored
  • [routine] Function URL stored in SSM Parameter Store as sensitive value for secure retrieval by other services

@Alexanderamiri Alexanderamiri merged commit 63b0549 into main Mar 13, 2026
3 checks passed
@Alexanderamiri Alexanderamiri deleted the fix/password-set-boundary branch March 13, 2026 22:52
Alexanderamiri added a commit that referenced this pull request May 9, 2026
## Summary
- **OIDC trust policy**: apply job uses `environment: production`, which
makes GitHub send `repo:javaBin/platform:environment:production` as the
sub claim instead of `repo:javaBin/platform:ref:refs/heads/main`. Added
both formats.
- **Permissions boundary**: `javabin-password-set` role needs
`permissions_boundary` — the developer boundary blocks creating roles
without it.
- **Reverts v5 pin**: #57 pinned credentials to v5, but v5 vs v6 wasn't
the issue — it was the sub claim mismatch.

## Test plan
- [ ] Apply succeeds — creates password-set Lambda + role + function URL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant