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

[Task]: Analytics deploy cleanup: DRY the terraform service modules #1931

Closed
1 task
coilysiren opened this issue May 6, 2024 · 0 comments · Fixed by #1946
Closed
1 task

[Task]: Analytics deploy cleanup: DRY the terraform service modules #1931

coilysiren opened this issue May 6, 2024 · 0 comments · Fixed by #1946
Assignees
Labels
project: grants.gov Grants.gov Modernization tickets refinement

Comments

@coilysiren
Copy link
Collaborator

Summary

//

Acceptance criteria

  • duplicate service modules removed
@coilysiren coilysiren added the project: grants.gov Grants.gov Modernization tickets label May 6, 2024
@coilysiren coilysiren self-assigned this May 6, 2024
coilysiren added a commit that referenced this issue May 6, 2024
## Summary

Partially addresses
#1931

Follows up on #1856

### Time to review: __10 mins__

## Changes proposed

The goal of this PR is to get metabase using the same `modules/service`
module the dev API and dev frontend are using. Metabase has a few
fundamental settings that need to be changed relative to the dev API, so
this PR makes those changes. With those changes made,
`modules/metabase-service` can be removed.

The changes are:

- conditionally add `ecr` pull permissions
- conditionally create database access roles (Metabase cannot use IAM to
access the database, and therefore does not need these roles)
- modifies the load balancer healthcheck path
- conditionally removes the container healthcheck, for simplicity
- allow pulling an image from a full `image_repository_url` rather than
a partial `image_repository_name`
- make `readonlyRootFilesystem` a boolean variable, defaults to true
- make `linuxParameters` variable, defaults to true

## Context for reviewers

This is a complex PR, but ideally it is a no-op from a functional POV.
The goal is to get these two services to use the same module, without
truly changing anything. On that note, here are the terraform diffs:

<details>

```
terraform apply -var="environment_name=dev" -var="image_tag=v0.49.7"
module.service.data.aws_region.current: Reading...
module.service.aws_cloudwatch_log_group.WafWebAclLoggroup: Refreshing state... [id=aws-waf-logs-wafv2-web-acl-metabase-dev]
module.service.aws_ecs_cluster.cluster: Refreshing state... [id=arn:aws:ecs:us-east-1:315341936575:cluster/metabase-dev]
data.aws_vpc.network: Reading...
module.service.data.aws_region.current: Read complete after 0s [id=us-east-1]
data.aws_rds_cluster.db_cluster: Reading...
module.service.aws_cloudwatch_log_group.service_logs: Refreshing state... [id=service/metabase-dev]
module.service.data.aws_iam_policy_document.ecs_tasks_assume_role_policy: Reading...
module.service.data.aws_caller_identity.current: Reading...
module.service.aws_s3_bucket.access_logs: Refreshing state... [id=metabase-dev-access-logs20240426185617520000000004]
module.service.data.aws_iam_policy_document.ecs_tasks_assume_role_policy: Read complete after 0s [id=597844978]
module.service.aws_s3_bucket.general_purpose: Refreshing state... [id=metabase-dev-general-purpose20240426185617519900000003]
module.service.aws_iam_role.app_service: Refreshing state... [id=metabase-dev-app]
module.service.data.aws_caller_identity.current: Read complete after 0s [id=315341936575]
module.service.aws_iam_role.task_executor: Refreshing state... [id=metabase-dev-task-executor]
module.service.aws_wafv2_web_acl.waf: Refreshing state... [id=db82e49c-a917-4e30-9a1c-a5f78749bf5a]
module.service.data.aws_iam_policy_document.WafWebAclLoggingDoc: Reading...
module.service.data.aws_iam_policy_document.WafWebAclLoggingDoc: Read complete after 0s [id=2816859187]
module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy: Refreshing state... [id=analytics-webacl-policy]
data.aws_rds_cluster.db_cluster: Read complete after 0s [id=analytics-dev]
module.service.data.aws_iam_policy_document.task_executor: Reading...
module.service.data.aws_iam_policy_document.task_executor: Read complete after 0s [id=450173802]
module.service.aws_iam_role_policy.task_executor: Refreshing state... [id=metabase-dev-task-executor:metabase-dev-task-executor-role-policy]
data.aws_vpc.network: Read complete after 1s [id=vpc-08f522c5cc442d126]
data.aws_subnets.public: Reading...
data.aws_subnets.private: Reading...
module.service.aws_security_group.alb: Refreshing state... [id=sg-0c4edfb171385bc21]
module.service.aws_lb_target_group.app_tg: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:targetgroup/app-20240426205400352000000001/debfd3d4006fa28d]
data.aws_subnets.public: Read complete after 0s [id=us-east-1]
data.aws_subnets.private: Read complete after 0s [id=us-east-1]
module.service.aws_security_group_rule.http_ingress: Refreshing state... [id=sgrule-2874082577]
module.service.aws_security_group.app: Refreshing state... [id=sg-0f0416c323a602fa8]
module.service.aws_s3_bucket_public_access_block.general_purpose: Refreshing state... [id=metabase-dev-general-purpose20240426185617519900000003]
module.service.aws_s3_bucket_server_side_encryption_configuration.general_purpose_encryption: Refreshing state... [id=metabase-dev-general-purpose20240426185617519900000003]
module.service.aws_s3_bucket_lifecycle_configuration.general_purpose: Refreshing state... [id=metabase-dev-general-purpose20240426185617519900000003]
module.service.aws_ecs_task_definition.app: Refreshing state... [id=metabase-dev]
module.service.data.aws_iam_policy_document.general_purpose_put_access: Reading...
module.service.data.aws_iam_policy_document.general_purpose_put_access: Read complete after 0s [id=3943424410]
module.service.aws_s3_bucket_policy.general_purpose: Refreshing state... [id=metabase-dev-general-purpose20240426185617519900000003]
module.service.aws_s3_bucket_lifecycle_configuration.access_logs: Refreshing state... [id=metabase-dev-access-logs20240426185617520000000004]
module.service.aws_s3_bucket_public_access_block.access_logs: Refreshing state... [id=metabase-dev-access-logs20240426185617520000000004]
module.service.aws_s3_bucket_server_side_encryption_configuration.encryption: Refreshing state... [id=metabase-dev-access-logs20240426185617520000000004]
module.service.data.aws_iam_policy_document.access_logs_put_access: Reading...
module.service.data.aws_iam_policy_document.access_logs_put_access: Read complete after 0s [id=1668394058]
module.service.aws_vpc_security_group_ingress_rule.db_ingress_from_service[0]: Refreshing state... [id=sgr-0faef727f6ef997d3]
module.service.aws_s3_bucket_policy.access_logs: Refreshing state... [id=metabase-dev-access-logs20240426185617520000000004]
module.service.aws_ecs_service.app: Refreshing state... [id=arn:aws:ecs:us-east-1:315341936575:service/metabase-dev/metabase-dev]
module.service.aws_lb.alb: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:loadbalancer/app/metabase-dev/be07ae73a69bf068]
module.service.aws_lb_listener.alb_listener_http: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:listener/app/metabase-dev/be07ae73a69bf068/bb6a012d93ffc20b]
module.service.aws_lb_listener_rule.app_http_forward: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:listener-rule/app/metabase-dev/be07ae73a69bf068/bb6a012d93ffc20b/e66e8aec66734db2]
module.service.aws_wafv2_web_acl_association.WafWebAclAssociation: Refreshing state... [id=arn:aws:wafv2:us-east-1:315341936575:regional/webacl/metabase-dev-wafv2-web-acl/db82e49c-a917-4e30-9a1c-a5f78749bf5a,arn:aws:elasticloadbalancing:us-east-1:315341936575:loadbalancer/app/metabase-dev/be07ae73a69bf068]
module.service.aws_wafv2_web_acl_logging_configuration.WafWebAclLogging: Refreshing state... [id=arn:aws:wafv2:us-east-1:315341936575:regional/webacl/metabase-dev-wafv2-web-acl/db82e49c-a917-4e30-9a1c-a5f78749bf5a]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy must be replaced
-/+ resource "aws_cloudwatch_log_resource_policy" "WafWebAclLoggingPolicy" {
      ~ id              = "analytics-webacl-policy" -> (known after apply)
      ~ policy_name     = "analytics-webacl-policy" -> "service-metabase-dev-webacl-policy" # forces replacement
        # (1 unchanged attribute hidden)
    }

  # module.service.aws_ecs_service.app will be updated in-place
  ~ resource "aws_ecs_service" "app" {
        id                                 = "arn:aws:ecs:us-east-1:315341936575:service/metabase-dev/metabase-dev"
        name                               = "metabase-dev"
        tags                               = {}
      ~ task_definition                    = "arn:aws:ecs:us-east-1:315341936575:task-definition/metabase-dev:8" -> (known after apply)
        # (15 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.service.aws_ecs_task_definition.app must be replaced
-/+ resource "aws_ecs_task_definition" "app" {
      ~ arn                      = "arn:aws:ecs:us-east-1:315341936575:task-definition/metabase-dev:8" -> (known after apply)
      ~ arn_without_revision     = "arn:aws:ecs:us-east-1:315341936575:task-definition/metabase-dev" -> (known after apply)
      ~ container_definitions    = jsonencode(
          ~ [
              ~ {
                  ~ environment            = [
                      + {
                          + name  = "AWS_REGION"
                          + value = "us-east-1"
                        },
                      + {
                          + name  = "DB_HOST"
                          + value = "analytics-dev.cluster-crj70bc9j3t7.us-east-1.rds.amazonaws.com"
                        },
                      + {
                          + name  = "DB_NAME"
                          + value = "app"
                        },
                      + {
                          + name  = "DB_PORT"
                          + value = "5432"
                        },
                      + {
                          + name  = "DB_SCHEMA"
                          + value = "analytics"
                        },
                      + {
                          + name  = "DB_USER"
                          + value = "app"
                        },
                        {
                            name  = "MB_DB_DBNAME"
                            value = "metabase"
                        },
                        # (2 unchanged elements hidden)
                        {
                            name  = "MB_DB_TYPE"
                            value = "postgres"
                        },
                      + {
                          + name  = "PORT"
                          + value = "3000"
                        },
                      + {
                          + name  = "S3_BUCKET_ARN"
                          + value = "arn:aws:s3:::metabase-dev-general-purpose20240426185617519900000003"
                        },
                    ]
                  - mountPoints            = []
                    name                   = "metabase-dev"
                  ~ portMappings           = [
                      ~ {
                          - hostPort      = 3000
                          - protocol      = "tcp"
                            # (1 unchanged attribute hidden)
                        },
                    ]
                  - systemControls         = []
                  - volumesFrom            = []
                    # (7 unchanged attributes hidden)
                },
            ] # forces replacement
        )
      ~ id                       = "metabase-dev" -> (known after apply)
      ~ revision                 = 8 -> (known after apply)
      - tags                     = {} -> null
        # (11 unchanged attributes hidden)
    }

  # module.service.aws_iam_role.migrator_task[0] will be created
  + resource "aws_iam_role" "migrator_task" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = [
                              + "states.amazonaws.com",
                              + "scheduler.amazonaws.com",
                              + "ecs-tasks.amazonaws.com",
                            ]
                        }
                      + Sid       = "ECSTasksAssumeRole"
                    },
                ]
              + 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                  = "metabase-dev-migrator"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = {
          + "description"         = "Application resources created in dev environment"
          + "environment"         = "dev"
          + "owner"               = "navapbc"
          + "project"             = "simpler-grants-gov"
          + "repository"          = "https://github.com/HHS/simpler-grants-gov"
          + "terraform"           = "true"
          + "terraform_workspace" = "default"
        }
      + unique_id             = (known after apply)
    }

  # module.service.aws_iam_role_policy.task_executor will be updated in-place
  ~ resource "aws_iam_role_policy" "task_executor" {
        id          = "metabase-dev-task-executor:metabase-dev-task-executor-role-policy"
        name        = "metabase-dev-task-executor-role-policy"
      ~ policy      = jsonencode(
          ~ {
              ~ Statement = [
                    # (6 unchanged elements hidden)
                    {
                        Action   = "states:StartExecution"
                        Effect   = "Allow"
                        Resource = "arn:aws:states:*:*:stateMachine:*"
                        Sid      = "StepFunctionsStartExecution"
                    },
                  + {
                      + Action   = "ecr:GetAuthorizationToken"
                      + Effect   = "Allow"
                      + Resource = "*"
                      + Sid      = "ECRAuth"
                    },
                    {
                        Action   = "ssm:GetParameters"
                        Effect   = "Allow"
                        Resource = [
                            "arn:aws:ssm:*:*:parameter/metabase/dev/db_user",
                            "arn:aws:ssm:*:*:parameter/metabase/dev/db_pass",
                        ]
                        Sid      = "SecretsAccess"
                    },
                ]
                # (1 unchanged attribute hidden)
            }
        )
        # (2 unchanged attributes hidden)
    }

Plan: 3 to add, 2 to change, 2 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy: Destroying... [id=analytics-webacl-policy]
module.service.aws_ecs_task_definition.app: Destroying... [id=metabase-dev]
module.service.aws_iam_role_policy.task_executor: Modifying... [id=metabase-dev-task-executor:metabase-dev-task-executor-role-policy]
module.service.aws_iam_role.migrator_task[0]: Creating...
module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy: Destruction complete after 0s
module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy: Creating...
module.service.aws_ecs_task_definition.app: Destruction complete after 0s
module.service.aws_ecs_task_definition.app: Creating...
module.service.aws_iam_role_policy.task_executor: Modifications complete after 0s [id=metabase-dev-task-executor:metabase-dev-task-executor-role-policy]
module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy: Creation complete after 0s [id=service-metabase-dev-webacl-policy]
module.service.aws_ecs_task_definition.app: Creation complete after 1s [id=metabase-dev]
module.service.aws_ecs_service.app: Modifying... [id=arn:aws:ecs:us-east-1:315341936575:service/metabase-dev/metabase-dev]
module.service.aws_iam_role.migrator_task[0]: Creation complete after 1s [id=metabase-dev-migrator]
module.service.aws_ecs_service.app: Modifications complete after 1s [id=arn:aws:ecs:us-east-1:315341936575:service/metabase-dev/metabase-dev]

Apply complete! Resources: 3 added, 2 changed, 2 destroyed.

Outputs:

image_tag = "v0.49.7"
```

</details>
<details>

```
terraform apply -var="environment_name=dev"
data.terraform_remote_state.current_image_tag[0]: Reading...
data.aws_iam_policy.migrator_db_access_policy[0]: Reading...
module.monitoring.aws_cloudwatch_log_metric_filter.service_error_filter: Refreshing state... [id=service-error-filter]
data.aws_vpc.network: Reading...
data.aws_rds_cluster.db_cluster[0]: Reading...
module.service.data.aws_iam_policy_document.ecs_tasks_assume_role_policy: Reading...
module.monitoring.aws_sns_topic.this: Refreshing state... [id=arn:aws:sns:us-east-1:315341936575:api-dev-monitoring]
module.service.aws_s3_bucket.general_purpose: Refreshing state... [id=api-dev-general-purpose20240416221336163000000001]
module.service.data.aws_iam_policy_document.ecs_tasks_assume_role_policy: Read complete after 0s [id=597844978]
module.service.aws_s3_bucket.access_logs: Refreshing state... [id=api-dev-access-logs20231023213552646900000003]
module.service.aws_cloudwatch_log_group.WafWebAclLoggroup: Refreshing state... [id=aws-waf-logs-wafv2-web-acl-api-dev]
module.service.aws_wafv2_web_acl.waf: Refreshing state... [id=a13139a8-fb10-4545-89fb-924417495223]
module.service.data.aws_caller_identity.current: Reading...
module.service.data.aws_caller_identity.current: Read complete after 0s [id=315341936575]
module.service.aws_cloudwatch_log_group.service_logs: Refreshing state... [id=service/api-dev]
data.aws_iam_policy.app_db_access_policy[0]: Reading...
aws_cloudwatch_log_group.copy_oracle_data: Refreshing state... [id=/aws/vendedlogs/states/api-dev-copy-oracle-data20240405180135310900000001]
module.service.aws_ecs_cluster.cluster: Refreshing state... [id=arn:aws:ecs:us-east-1:315341936575:cluster/api-dev]
data.aws_rds_cluster.db_cluster[0]: Read complete after 0s [id=api-dev]
module.service.data.aws_region.current: Reading...
module.service.data.aws_region.current: Read complete after 0s [id=us-east-1]
module.service.data.aws_ecr_repository.app[0]: Reading...
aws_scheduler_schedule_group.copy_oracle_data: Refreshing state... [id=api-dev-copy-oracle-data]
data.terraform_remote_state.current_image_tag[0]: Read complete after 1s
module.service.aws_iam_role.task_executor: Refreshing state... [id=api-dev-task-executor]
data.aws_vpc.network: Read complete after 0s [id=vpc-08f522c5cc442d126]
module.service.aws_iam_role.app_service: Refreshing state... [id=api-dev-app]
module.monitoring.aws_cloudwatch_metric_alarm.service_errors: Refreshing state... [id=api-dev-errors]
module.monitoring.aws_sns_topic_subscription.email_integration["grantsalerts@navapbc.com"]: Refreshing state... [id=arn:aws:sns:us-east-1:315341936575:api-dev-monitoring:4f5f4bcf-9458-464b-a675-17f6803695dc]
module.service.data.aws_iam_policy_document.WafWebAclLoggingDoc: Reading...
module.service.data.aws_iam_policy_document.WafWebAclLoggingDoc: Read complete after 0s [id=919045586]
data.aws_subnets.private: Reading...
data.aws_subnets.public: Reading...
module.service.aws_lb_target_group.app_tg: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:targetgroup/app-20240129204404286300000001/2225bef73ea80162]
data.aws_subnets.private: Read complete after 0s [id=us-east-1]
module.service.aws_security_group.alb: Refreshing state... [id=sg-025e1dd290c12d572]
data.aws_subnets.public: Read complete after 0s [id=us-east-1]
module.service.aws_s3_bucket_server_side_encryption_configuration.encryption: Refreshing state... [id=api-dev-access-logs20231023213552646900000003]
module.service.data.aws_iam_policy_document.access_logs_put_access: Reading...
module.service.aws_s3_bucket_lifecycle_configuration.access_logs: Refreshing state... [id=api-dev-access-logs20231023213552646900000003]
module.service.data.aws_iam_policy_document.access_logs_put_access: Read complete after 0s [id=2049148182]
module.service.aws_s3_bucket_public_access_block.access_logs: Refreshing state... [id=api-dev-access-logs20231023213552646900000003]
module.service.aws_s3_bucket_policy.access_logs: Refreshing state... [id=api-dev-access-logs20231023213552646900000003]
module.service.aws_s3_bucket_lifecycle_configuration.general_purpose: Refreshing state... [id=api-dev-general-purpose20240416221336163000000001]
module.service.aws_s3_bucket_server_side_encryption_configuration.general_purpose_encryption: Refreshing state... [id=api-dev-general-purpose20240416221336163000000001]
module.service.data.aws_iam_policy_document.general_purpose_put_access: Reading...
module.service.data.aws_iam_policy_document.general_purpose_put_access: Read complete after 0s [id=612448226]
module.service.aws_s3_bucket_public_access_block.general_purpose: Refreshing state... [id=api-dev-general-purpose20240416221336163000000001]
module.service.aws_security_group_rule.http_ingress: Refreshing state... [id=sgrule-69662097]
module.service.aws_security_group.app: Refreshing state... [id=sg-0eab49e76a34379f9]
module.service.aws_s3_bucket_policy.general_purpose: Refreshing state... [id=api-dev-general-purpose20240416221336163000000001]
module.service.aws_lb.alb: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:loadbalancer/app/api-dev/48f2e65279b967a5]
module.service.aws_lb_listener.alb_listener_http: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:listener/app/api-dev/48f2e65279b967a5/d4ce6505b9614ba0]
module.monitoring.aws_cloudwatch_metric_alarm.high_load_balancer_http_5xx_count: Refreshing state... [id=api-dev-high-load-balancer-5xx-count]
module.monitoring.aws_cloudwatch_metric_alarm.high_app_response_time: Refreshing state... [id=api-dev-high-app-response-time]
module.monitoring.aws_cloudwatch_metric_alarm.high_app_http_5xx_count: Refreshing state... [id=api-dev-high-app-5xx-count]
data.aws_iam_policy.migrator_db_access_policy[0]: Read complete after 2s [id=arn:aws:iam::315341936575:policy/api-dev-migrator-access]
data.aws_iam_policy.app_db_access_policy[0]: Read complete after 2s [id=arn:aws:iam::315341936575:policy/api-dev-app-access]
module.service.aws_iam_role.migrator_task[0]: Refreshing state... [id=api-dev-migrator]
module.service.aws_vpc_security_group_ingress_rule.db_ingress_from_service[0]: Refreshing state... [id=sgr-024fcce0dd2b24824]
module.service.data.aws_ecr_repository.app[0]: Read complete after 2s [id=simpler-grants-gov-api]
module.service.aws_iam_role_policy_attachment.app_service_db_access[0]: Refreshing state... [id=api-dev-app-20231023230412768300000001]
module.service.data.aws_iam_policy_document.task_executor: Reading...
module.service.data.aws_iam_policy_document.task_executor: Read complete after 0s [id=3249190051]
module.service.aws_ecs_task_definition.app: Refreshing state... [id=api-dev]
module.service.aws_iam_role_policy.task_executor: Refreshing state... [id=api-dev-task-executor:api-dev-task-executor-role-policy]
aws_sfn_state_machine.copy_oracle_data: Refreshing state... [id=arn:aws:states:us-east-1:315341936575:stateMachine:api-dev-copy-oracle-data]
module.service.aws_ecs_service.app: Refreshing state... [id=arn:aws:ecs:us-east-1:315341936575:service/api-dev/api-dev]
module.service.aws_iam_role_policy_attachment.migrator_db_access[0]: Refreshing state... [id=api-dev-migrator-20231023230412789800000002]
module.service.aws_lb_listener_rule.app_http_forward: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:listener-rule/app/api-dev/48f2e65279b967a5/d4ce6505b9614ba0/009594b77c825b5a]
module.service.aws_wafv2_web_acl_association.WafWebAclAssociation: Refreshing state... [id=arn:aws:wafv2:us-east-1:315341936575:regional/webacl/api-dev-wafv2-web-acl/a13139a8-fb10-4545-89fb-924417495223,arn:aws:elasticloadbalancing:us-east-1:315341936575:loadbalancer/app/api-dev/48f2e65279b967a5]
module.service.aws_wafv2_web_acl_logging_configuration.WafWebAclLogging: Refreshing state... [id=arn:aws:wafv2:us-east-1:315341936575:regional/webacl/api-dev-wafv2-web-acl/a13139a8-fb10-4545-89fb-924417495223]
aws_scheduler_schedule.copy_oracle_data: Refreshing state... [id=api-dev-copy-oracle-data/api-dev-copy-oracle-data]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # aws_scheduler_schedule.copy_oracle_data will be updated in-place
  ~ resource "aws_scheduler_schedule" "copy_oracle_data" {
        id                           = "api-dev-copy-oracle-data/api-dev-copy-oracle-data"
        name                         = "api-dev-copy-oracle-data"
      ~ state                        = "DISABLED" -> "ENABLED"
        # (9 unchanged attributes hidden)

        # (2 unchanged blocks hidden)
    }

  # aws_sfn_state_machine.copy_oracle_data will be updated in-place
  ~ resource "aws_sfn_state_machine" "copy_oracle_data" {
      ~ definition                = jsonencode(
            {
              - StartAt = "ExecuteECSTask"
              - States  = {
                  - ExecuteECSTask = {
                      - End        = true
                      - Parameters = {
                          - Cluster              = "arn:aws:ecs:us-east-1:315341936575:cluster/api-dev"
                          - LaunchType           = "FARGATE"
                          - NetworkConfiguration = {
                              - AwsvpcConfiguration = {
                                  - SecurityGroups = [
                                      - "sg-0eab49e76a34379f9",
                                    ]
                                  - Subnets        = [
                                      - "subnet-0a5ea667d3751639f",
                                      - "subnet-068ede7dcfd9469ab",
                                      - "subnet-019f469ba97dc6ec7",
                                    ]
                                }
                            }
                          - Overrides            = {
                              - ContainerOverrides = [
                                  - {
                                      - Command     = [
                                          - "poetry",
                                          - "run",
                                          - "flask",
                                          - "data-migration",
                                          - "copy-oracle-data",
                                        ]
                                      - Environment = [
                                          - {
                                              - Name  = "FLASK_APP"
                                              - Value = "src.app:create_app()"
                                            },
                                        ]
                                      - Name        = "api-dev"
                                    },
                                ]
                            }
                          - TaskDefinition       = "arn:aws:ecs:us-east-1:315341936575:task-definition/api-dev:148"
                        }
                      - Resource   = "arn:aws:states:::ecs:runTask.sync"
                      - Type       = "Task"
                    }
                }
            }
        ) -> (known after apply)
        id                        = "arn:aws:states:us-east-1:315341936575:stateMachine:api-dev-copy-oracle-data"
        name                      = "api-dev-copy-oracle-data"
        tags                      = {}
        # (11 unchanged attributes hidden)

        # (2 unchanged blocks hidden)
    }

  # module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy will be created
  + resource "aws_cloudwatch_log_resource_policy" "WafWebAclLoggingPolicy" {
      + id              = (known after apply)
      + policy_document = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = [
                          + "logs:PutLogEvents",
                          + "logs:CreateLogStream",
                        ]
                      + Condition = {
                          + ArnLike      = {
                              + "aws:SourceArn" = "arn:aws:logs:us-east-1:315341936575:*"
                            }
                          + StringEquals = {
                              + "aws:SourceAccount" = "315341936575"
                            }
                        }
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "delivery.logs.amazonaws.com"
                        }
                      + Resource  = "arn:aws:logs:us-east-1:315341936575:log-group:aws-waf-logs-wafv2-web-acl-api-dev:*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + policy_name     = "service-api-dev-webacl-policy"
    }

  # module.service.aws_ecs_service.app will be updated in-place
  ~ resource "aws_ecs_service" "app" {
        id                                 = "arn:aws:ecs:us-east-1:315341936575:service/api-dev/api-dev"
        name                               = "api-dev"
        tags                               = {}
      ~ task_definition                    = "arn:aws:ecs:us-east-1:315341936575:task-definition/api-dev:148" -> (known after apply)
        # (15 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.service.aws_ecs_task_definition.app must be replaced
-/+ resource "aws_ecs_task_definition" "app" {
      ~ arn                      = "arn:aws:ecs:us-east-1:315341936575:task-definition/api-dev:148" -> (known after apply)
      ~ arn_without_revision     = "arn:aws:ecs:us-east-1:315341936575:task-definition/api-dev" -> (known after apply)
      ~ container_definitions    = jsonencode(
          ~ [
              ~ {
                  ~ linuxParameters        = {
                      ~ capabilities       = {
                          - add  = []
                            # (1 unchanged attribute hidden)
                        }
                        # (1 unchanged attribute hidden)
                    }
                  - mountPoints            = []
                    name                   = "api-dev"
                  ~ portMappings           = [
                      ~ {
                          - hostPort      = 8000
                          - protocol      = "tcp"
                            # (1 unchanged attribute hidden)
                        },
                    ]
                  - systemControls         = []
                  - volumesFrom            = []
                    # (9 unchanged attributes hidden)
                },
            ] # forces replacement
        )
      ~ id                       = "api-dev" -> (known after apply)
      ~ revision                 = 148 -> (known after apply)
      - tags                     = {} -> null
        # (11 unchanged attributes hidden)
    }

Plan: 2 to add, 3 to change, 1 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.service.aws_ecs_task_definition.app: Destroying... [id=api-dev]
module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy: Creating...
module.service.aws_ecs_task_definition.app: Destruction complete after 1s
module.service.aws_ecs_task_definition.app: Creating...
module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy: Creation complete after 1s [id=service-api-dev-webacl-policy]
module.service.aws_ecs_task_definition.app: Creation complete after 0s [id=api-dev]
aws_sfn_state_machine.copy_oracle_data: Modifying... [id=arn:aws:states:us-east-1:315341936575:stateMachine:api-dev-copy-oracle-data]
module.service.aws_ecs_service.app: Modifying... [id=arn:aws:ecs:us-east-1:315341936575:service/api-dev/api-dev]
module.service.aws_ecs_service.app: Modifications complete after 1s [id=arn:aws:ecs:us-east-1:315341936575:service/api-dev/api-dev]
aws_sfn_state_machine.copy_oracle_data: Modifications complete after 1s [id=arn:aws:states:us-east-1:315341936575:stateMachine:api-dev-copy-oracle-data]
aws_scheduler_schedule.copy_oracle_data: Modifying... [id=api-dev-copy-oracle-data/api-dev-copy-oracle-data]
aws_scheduler_schedule.copy_oracle_data: Modifications complete after 1s [id=api-dev-copy-oracle-data/api-dev-copy-oracle-data]

Apply complete! Resources: 2 added, 3 changed, 1 destroyed.

Outputs:

application_log_group = "service/api-dev"
application_log_stream_prefix = "api-dev"
image_tag = "25f818723bcdf215ef7da94e392b1b8fba34e3ff"
migrator_role_arn = "arn:aws:iam::315341936575:role/api-dev-migrator"
service_cluster_name = "api-dev"
service_endpoint = "http://api-dev-1839587515.us-east-1.elb.amazonaws.com"
service_name = "api-dev"
```

</details>
coilysiren added a commit that referenced this issue May 7, 2024
## Summary

Fixes #1931

### Time to review: __4 mins__

## Changes proposed

- Removes `modules/task-service` in favor of using `modules/service` for
the analytics package. I originally created `modules/task-service` as a
workaround to avoid needing to do this work, before I realized how easy
it would be!
- Adds `enable_load_balancer` to enable the ability to avoid deploying a
load balancer
- Adds `count = var.enable_load_balancer ? 1 : 0` to a every load
balancer and WAF resource

## Amazing Discovery!

In older versions of terraform, adding a `count` to a `resource` would
force you to do a `terraform state mv` [or a `moved`
block](https://developer.hashicorp.com/terraform/tutorials/configuration-language/move-config#move-your-resources-with-the-moved-configuration-block)
to keep the resource intact. Apparently in newer versions of terraform,
this is no longer the case!!! It now automatically detects that you have
moved a resource. That detection looks like so:

```
  # module.service.aws_lb.alb has moved to module.service.aws_lb.alb[0]
    resource "aws_lb" "alb" {
        id                                                           = "..."
        name                                                         = "api-dev"
        tags                                                         = {}
        # (25 unchanged attributes hidden)

        # (5 unchanged blocks hidden)
    }
```

Beacuse of this, this PR was MUCH EASIER than I thought it would be! I'm
so happy that we are using a recent version of terraform!

## `terraform plan` inside of `infra/analytics/service`

<details>

```
terraform apply -var="environment_name=dev"
data.terraform_remote_state.current_image_tag[0]: Reading...
data.aws_iam_policy.app_db_access_policy[0]: Reading...
data.aws_vpc.network: Reading...
module.service.data.aws_ecr_repository.app[0]: Reading...
module.service.data.aws_region.current: Reading...
data.aws_rds_cluster.db_cluster[0]: Reading...
module.service.data.aws_caller_identity.current: Reading...
data.aws_iam_policy.migrator_db_access_policy[0]: Reading...
aws_scheduler_schedule_group.sprint_reports: Refreshing state... [id=analytics-dev-sprint-reports]
module.service.data.aws_region.current: Read complete after 0s [id=us-east-1]
aws_cloudwatch_log_group.sprint_reports: Refreshing state... [id=/aws/vendedlogs/states/analytics-dev-sprint-reports20240402190032717900000001]
module.service.aws_cloudwatch_log_group.service_logs: Refreshing state... [id=service/analytics-dev]
module.service.data.aws_caller_identity.current: Read complete after 0s [id=315341936575]
module.service.aws_ecs_cluster.cluster: Refreshing state... [id=arn:aws:ecs:us-east-1:315341936575:cluster/analytics-dev]
module.service.data.aws_iam_policy_document.ecs_tasks_assume_role_policy: Reading...
module.service.data.aws_iam_policy_document.ecs_tasks_assume_role_policy: Read complete after 0s [id=597844978]
module.service.aws_iam_role.app_service: Refreshing state... [id=analytics-dev-app]
module.service.aws_iam_role.task_executor: Refreshing state... [id=analytics-dev-task-executor]
data.aws_rds_cluster.db_cluster[0]: Read complete after 0s [id=analytics-dev]
module.service.aws_iam_role.migrator_task[0]: Refreshing state... [id=analytics-dev-migrator]
data.terraform_remote_state.current_image_tag[0]: Read complete after 1s
module.service.data.aws_ecr_repository.app[0]: Read complete after 1s [id=simpler-grants-gov-analytics]
module.service.aws_ecs_task_definition.app: Refreshing state... [id=analytics-dev]
module.service.data.aws_iam_policy_document.task_executor: Reading...
module.service.data.aws_iam_policy_document.task_executor: Read complete after 0s [id=3572404559]
module.service.aws_iam_role_policy.task_executor: Refreshing state... [id=analytics-dev-task-executor:analytics-dev-task-executor-role-policy]
data.aws_vpc.network: Read complete after 1s [id=vpc-08f522c5cc442d126]
data.aws_subnets.public: Reading...
data.aws_subnets.private: Reading...
module.service.aws_security_group.app: Refreshing state... [id=sg-0ed2e3fe9a482683c]
data.aws_subnets.public: Read complete after 0s [id=us-east-1]
data.aws_subnets.private: Read complete after 0s [id=us-east-1]
module.service.aws_vpc_security_group_ingress_rule.db_ingress_from_service[0]: Refreshing state... [id=sgr-005d1c8947c789bd0]
aws_sfn_state_machine.sprint_reports: Refreshing state... [id=arn:aws:states:us-east-1:315341936575:stateMachine:analytics-dev-sprint-reports]
module.service.aws_ecs_service.app: Refreshing state... [id=arn:aws:ecs:us-east-1:315341936575:service/analytics-dev/analytics-dev]
aws_scheduler_schedule.sprint_reports: Refreshing state... [id=analytics-dev-sprint-reports/analytics-dev-sprint-reports]
data.aws_iam_policy.app_db_access_policy[0]: Read complete after 2s [id=arn:aws:iam::315341936575:policy/analytics-dev-app-access]
module.service.aws_iam_role_policy_attachment.app_service_db_access[0]: Refreshing state... [id=analytics-dev-app-20240328214813228600000005]
data.aws_iam_policy.migrator_db_access_policy[0]: Read complete after 2s [id=arn:aws:iam::315341936575:policy/analytics-dev-migrator-access]
module.service.aws_iam_role_policy_attachment.migrator_db_access[0]: Refreshing state... [id=analytics-dev-migrator-20240328214813227300000004]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
-/+ destroy and then create replacement
 <= read (data resources)

Terraform will perform the following actions:

  # aws_sfn_state_machine.sprint_reports will be updated in-place
  ~ resource "aws_sfn_state_machine" "sprint_reports" {
      ~ definition                = jsonencode(
            {
              - StartAt = "ExecuteECSTask"
              - States  = {
                  - ExecuteECSTask = {
                      - End        = true
                      - Parameters = {
                          - Cluster              = "arn:aws:ecs:us-east-1:315341936575:cluster/analytics-dev"
                          - LaunchType           = "FARGATE"
                          - NetworkConfiguration = {
                              - AwsvpcConfiguration = {
                                  - SecurityGroups = [
                                      - "sg-0ed2e3fe9a482683c",
                                    ]
                                  - Subnets        = [
                                      - "subnet-0a5ea667d3751639f",
                                      - "subnet-068ede7dcfd9469ab",
                                      - "subnet-019f469ba97dc6ec7",
                                    ]
                                }
                            }
                          - Overrides            = {
                              - ContainerOverrides = [
                                  - {
                                      - Command     = [
                                          - "make",
                                          - "gh-data-export",
                                          - "sprint-reports",
                                        ]
                                      - Environment = [
                                          - {
                                              - Name  = "PY_RUN_APPROACH"
                                              - Value = "local"
                                            },
                                          - {
                                              - Name  = "SPRINT_FILE"
                                              - Value = "/tmp/sprint-data.json"
                                            },
                                          - {
                                              - Name  = "ISSUE_FILE"
                                              - Value = "/tmp/issue-data.json"
                                            },
                                          - {
                                              - Name  = "OUTPUT_DIR"
                                              - Value = "/tmp/"
                                            },
                                        ]
                                      - Name        = "analytics-dev"
                                    },
                                ]
                            }
                          - TaskDefinition       = "arn:aws:ecs:us-east-1:315341936575:task-definition/analytics-dev:29"
                        }
                      - Resource   = "arn:aws:states:::ecs:runTask.sync"
                      - Type       = "Task"
                    }
                }
            }
        ) -> (known after apply)
        id                        = "arn:aws:states:us-east-1:315341936575:stateMachine:analytics-dev-sprint-reports"
        name                      = "analytics-dev-sprint-reports"
        tags                      = {}
        # (11 unchanged attributes hidden)

        # (2 unchanged blocks hidden)
    }

  # module.service.data.aws_iam_policy_document.access_logs_put_access will be read during apply
  # (config refers to values not yet known)
 <= data "aws_iam_policy_document" "access_logs_put_access" {
      + id   = (known after apply)
      + json = (known after apply)

      + statement {
          + actions   = [
              + "s3:PutObject",
            ]
          + effect    = "Allow"
          + resources = [
              + (known after apply),
              + (known after apply),
            ]

          + principals {
              + identifiers = [
                  + "arn:aws:iam::127311923021:root",
                ]
              + type        = "AWS"
            }
        }
      + statement {
          + actions   = [
              + "s3:*",
            ]
          + effect    = "Deny"
          + resources = [
              + (known after apply),
              + (known after apply),
            ]
          + sid       = "AllowSSLRequestsOnly"

          + condition {
              + test     = "Bool"
              + values   = [
                  + "false",
                ]
              + variable = "aws:SecureTransport"
            }

          + principals {
              + identifiers = [
                  + "*",
                ]
              + type        = "AWS"
            }
        }
    }

  # module.service.data.aws_iam_policy_document.general_purpose_put_access will be read during apply
  # (config refers to values not yet known)
 <= data "aws_iam_policy_document" "general_purpose_put_access" {
      + id   = (known after apply)
      + json = (known after apply)

      + statement {
          + actions   = [
              + "s3:*",
            ]
          + effect    = "Allow"
          + resources = [
              + (known after apply),
              + (known after apply),
            ]

          + principals {
              + identifiers = [
                  + "arn:aws:iam::315341936575:role/analytics-dev-app",
                ]
              + type        = "AWS"
            }
        }
      + statement {
          + actions   = [
              + "s3:*",
            ]
          + effect    = "Deny"
          + resources = [
              + (known after apply),
              + (known after apply),
            ]
          + sid       = "AllowSSLRequestsOnly"

          + condition {
              + test     = "Bool"
              + values   = [
                  + "false",
                ]
              + variable = "aws:SecureTransport"
            }

          + principals {
              + identifiers = [
                  + "*",
                ]
              + type        = "AWS"
            }
        }
    }

  # module.service.aws_ecs_service.app will be updated in-place
  ~ resource "aws_ecs_service" "app" {
        id                                 = "arn:aws:ecs:us-east-1:315341936575:service/analytics-dev/analytics-dev"
        name                               = "analytics-dev"
        tags                               = {}
      ~ task_definition                    = "arn:aws:ecs:us-east-1:315341936575:task-definition/analytics-dev:29" -> (known after apply)
        # (15 unchanged attributes hidden)

        # (3 unchanged blocks hidden)
    }

  # module.service.aws_ecs_task_definition.app must be replaced
-/+ resource "aws_ecs_task_definition" "app" {
      ~ arn                      = "arn:aws:ecs:us-east-1:315341936575:task-definition/analytics-dev:29" -> (known after apply)
      ~ arn_without_revision     = "arn:aws:ecs:us-east-1:315341936575:task-definition/analytics-dev" -> (known after apply)
      ~ container_definitions    = jsonencode(
            [
              - {
                  - cpu                    = 1024
                  - environment            = [
                      - {
                          - name  = "ACTION"
                          - value = "show-results"
                        },
                      - {
                          - name  = "AWS_REGION"
                          - value = "us-east-1"
                        },
                      - {
                          - name  = "DB_HOST"
                          - value = "analytics-dev.cluster-crj70bc9j3t7.us-east-1.rds.amazonaws.com"
                        },
                      - {
                          - name  = "DB_NAME"
                          - value = "app"
                        },
                      - {
                          - name  = "DB_PORT"
                          - value = "5432"
                        },
                      - {
                          - name  = "DB_SCHEMA"
                          - value = "analytics"
                        },
                      - {
                          - name  = "DB_USER"
                          - value = "app"
                        },
                      - {
                          - name  = "PORT"
                          - value = "8000"
                        },
                    ]
                  - essential              = true
                  - image                  = "315341936575.dkr.ecr.us-east-1.amazonaws.com/simpler-grants-gov-analytics:58971a07c4956ad282182443a509354a40e92721"
                  - linuxParameters        = {
                      - capabilities       = {
                          - add  = []
                          - drop = [
                              - "ALL",
                            ]
                        }
                      - initProcessEnabled = true
                    }
                  - logConfiguration       = {
                      - logDriver = "awslogs"
                      - options   = {
                          - awslogs-group         = "service/analytics-dev"
                          - awslogs-region        = "us-east-1"
                          - awslogs-stream-prefix = "analytics-dev"
                        }
                    }
                  - memory                 = 2048
                  - mountPoints            = []
                  - name                   = "analytics-dev"
                  - portMappings           = []
                  - readonlyRootFilesystem = true
                  - secrets                = [
                      - {
                          - name      = "ANALYTICS_REPORTING_CHANNEL_ID"
                          - valueFrom = "/analytics/dev/reporting-channel-id"
                        },
                      - {
                          - name      = "ANALYTICS_SLACK_BOT_TOKEN"
                          - valueFrom = "/analytics/dev/slack-bot-token"
                        },
                      - {
                          - name      = "GH_TOKEN"
                          - valueFrom = "/analytics/dev/github-token"
                        },
                    ]
                  - systemControls         = []
                  - volumesFrom            = []
                },
            ] # forces replacement
        ) -> (known after apply) # forces replacement
      ~ id                       = "analytics-dev" -> (known after apply)
      ~ revision                 = 29 -> (known after apply)
      - tags                     = {} -> null
        # (11 unchanged attributes hidden)
    }

  # module.service.aws_s3_bucket.access_logs will be created
  + resource "aws_s3_bucket" "access_logs" {
      + acceleration_status         = (known after apply)
      + acl                         = (known after apply)
      + arn                         = (known after apply)
      + bucket                      = (known after apply)
      + bucket_domain_name          = (known after apply)
      + bucket_prefix               = "analytics-dev-access-logs"
      + bucket_regional_domain_name = (known after apply)
      + force_destroy               = false
      + hosted_zone_id              = (known after apply)
      + id                          = (known after apply)
      + object_lock_enabled         = (known after apply)
      + policy                      = (known after apply)
      + region                      = (known after apply)
      + request_payer               = (known after apply)
      + tags_all                    = {
          + "description"         = "Application resources created in dev environment"
          + "environment"         = "dev"
          + "owner"               = "navapbc"
          + "project"             = "simpler-grants-gov"
          + "repository"          = "https://github.com/HHS/simpler-grants-gov"
          + "terraform"           = "true"
          + "terraform_workspace" = "default"
        }
      + website_domain              = (known after apply)
      + website_endpoint            = (known after apply)
    }

  # module.service.aws_s3_bucket.general_purpose will be created
  + resource "aws_s3_bucket" "general_purpose" {
      + acceleration_status         = (known after apply)
      + acl                         = (known after apply)
      + arn                         = (known after apply)
      + bucket                      = (known after apply)
      + bucket_domain_name          = (known after apply)
      + bucket_prefix               = "analytics-dev-general-purpose"
      + bucket_regional_domain_name = (known after apply)
      + force_destroy               = false
      + hosted_zone_id              = (known after apply)
      + id                          = (known after apply)
      + object_lock_enabled         = (known after apply)
      + policy                      = (known after apply)
      + region                      = (known after apply)
      + request_payer               = (known after apply)
      + tags_all                    = {
          + "description"         = "Application resources created in dev environment"
          + "environment"         = "dev"
          + "owner"               = "navapbc"
          + "project"             = "simpler-grants-gov"
          + "repository"          = "https://github.com/HHS/simpler-grants-gov"
          + "terraform"           = "true"
          + "terraform_workspace" = "default"
        }
      + website_domain              = (known after apply)
      + website_endpoint            = (known after apply)
    }

  # module.service.aws_s3_bucket_lifecycle_configuration.access_logs will be created
  + resource "aws_s3_bucket_lifecycle_configuration" "access_logs" {
      + bucket = (known after apply)
      + id     = (known after apply)

      + rule {
          + id     = "AbortIncompleteUpload"
          + status = "Enabled"

          + abort_incomplete_multipart_upload {
              + days_after_initiation = 7
            }
        }
      + rule {
          + id     = "StorageClass"
          + status = "Enabled"

          + transition {
              + days          = 30
              + storage_class = "STANDARD_IA"
                # (1 unchanged attribute hidden)
            }
          + transition {
              + days          = 60
              + storage_class = "GLACIER"
                # (1 unchanged attribute hidden)
            }
        }
      + rule {
          + id     = "Expiration"
          + status = "Enabled"

          + expiration {
              + days                         = 2555
              + expired_object_delete_marker = (known after apply)
            }
        }
    }

  # module.service.aws_s3_bucket_lifecycle_configuration.general_purpose will be created
  + resource "aws_s3_bucket_lifecycle_configuration" "general_purpose" {
      + bucket = (known after apply)
      + id     = (known after apply)

      + rule {
          + id     = "AbortIncompleteUpload"
          + status = "Enabled"

          + abort_incomplete_multipart_upload {
              + days_after_initiation = 7
            }
        }
    }

  # module.service.aws_s3_bucket_policy.access_logs will be created
  + resource "aws_s3_bucket_policy" "access_logs" {
      + bucket = (known after apply)
      + id     = (known after apply)
      + policy = (known after apply)
    }

  # module.service.aws_s3_bucket_policy.general_purpose will be created
  + resource "aws_s3_bucket_policy" "general_purpose" {
      + bucket = (known after apply)
      + id     = (known after apply)
      + policy = (known after apply)
    }

  # module.service.aws_s3_bucket_public_access_block.access_logs will be created
  + resource "aws_s3_bucket_public_access_block" "access_logs" {
      + block_public_acls       = true
      + block_public_policy     = true
      + bucket                  = (known after apply)
      + id                      = (known after apply)
      + ignore_public_acls      = true
      + restrict_public_buckets = true
    }

  # module.service.aws_s3_bucket_public_access_block.general_purpose will be created
  + resource "aws_s3_bucket_public_access_block" "general_purpose" {
      + block_public_acls       = true
      + block_public_policy     = true
      + bucket                  = (known after apply)
      + id                      = (known after apply)
      + ignore_public_acls      = true
      + restrict_public_buckets = true
    }

  # module.service.aws_s3_bucket_server_side_encryption_configuration.encryption will be created
  + resource "aws_s3_bucket_server_side_encryption_configuration" "encryption" {
      + bucket = (known after apply)
      + id     = (known after apply)

      + rule {
          + bucket_key_enabled = true

          + apply_server_side_encryption_by_default {
              + sse_algorithm     = "aws:kms"
                # (1 unchanged attribute hidden)
            }
        }
    }

  # module.service.aws_s3_bucket_server_side_encryption_configuration.general_purpose_encryption will be created
  + resource "aws_s3_bucket_server_side_encryption_configuration" "general_purpose_encryption" {
      + bucket = (known after apply)
      + id     = (known after apply)

      + rule {
          + bucket_key_enabled = true

          + apply_server_side_encryption_by_default {
              + sse_algorithm     = "aws:kms"
                # (1 unchanged attribute hidden)
            }
        }
    }

  # module.service.aws_security_group.alb will be created
  + resource "aws_security_group" "alb" {
      + arn                    = (known after apply)
      + description            = "Allow TCP traffic to application load balancer"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Allow all outgoing traffic"
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = (known after apply)
      + name                   = (known after apply)
      + name_prefix            = "analytics-dev-alb"
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = {
          + "description"         = "Application resources created in dev environment"
          + "environment"         = "dev"
          + "owner"               = "navapbc"
          + "project"             = "simpler-grants-gov"
          + "repository"          = "https://github.com/HHS/simpler-grants-gov"
          + "terraform"           = "true"
          + "terraform_workspace" = "default"
        }
      + vpc_id                 = "vpc-08f522c5cc442d126"
    }

  # module.service.aws_security_group.app will be updated in-place
  ~ resource "aws_security_group" "app" {
        id                     = "sg-0ed2e3fe9a482683c"
      ~ ingress                = [
          + {
              + cidr_blocks      = []
              + description      = "Allow HTTP traffic to application container port"
              + from_port        = 8000
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = (known after apply)
              + self             = false
              + to_port          = 8000
            },
        ]
        name                   = "analytics-dev-app20240328231535754500000001"
        tags                   = {}
        # (8 unchanged attributes hidden)
    }

  # module.service.aws_security_group_rule.http_ingress will be created
  + resource "aws_security_group_rule" "http_ingress" {
      + cidr_blocks              = [
          + "0.0.0.0/0",
        ]
      + description              = "Allow HTTP traffic from public internet"
      + from_port                = 80
      + id                       = (known after apply)
      + protocol                 = "tcp"
      + security_group_id        = (known after apply)
      + security_group_rule_id   = (known after apply)
      + self                     = false
      + source_security_group_id = (known after apply)
      + to_port                  = 80
      + type                     = "ingress"
    }

Plan: 13 to add, 3 to change, 1 to destroy.
```

</details>

## `terraform plan` inside of `infra/api/service`

<details>

```
terraform plan -var="environment_name=dev"
data.terraform_remote_state.current_image_tag[0]: Reading...
data.aws_iam_policy.migrator_db_access_policy[0]: Reading...
data.aws_vpc.network: Reading...
module.service.data.aws_iam_policy_document.ecs_tasks_assume_role_policy: Reading...
data.aws_rds_cluster.db_cluster[0]: Reading...
aws_scheduler_schedule_group.copy_oracle_data: Refreshing state... [id=api-dev-copy-oracle-data]
module.service.aws_cloudwatch_log_group.WafWebAclLoggroup[0]: Refreshing state... [id=aws-waf-logs-wafv2-web-acl-api-dev]
module.service.aws_ecs_cluster.cluster: Refreshing state... [id=arn:aws:ecs:us-east-1:315341936575:cluster/api-dev]
aws_cloudwatch_log_group.copy_oracle_data: Refreshing state... [id=/aws/vendedlogs/states/api-dev-copy-oracle-data20240405180135310900000001]
module.service.data.aws_iam_policy_document.ecs_tasks_assume_role_policy: Read complete after 0s [id=597844978]
module.service.aws_s3_bucket.general_purpose: Refreshing state... [id=api-dev-general-purpose20240416221336163000000001]
data.aws_iam_policy.app_db_access_policy[0]: Reading...
module.service.aws_cloudwatch_log_group.service_logs: Refreshing state... [id=service/api-dev]
module.service.data.aws_caller_identity.current: Reading...
module.monitoring.aws_cloudwatch_log_metric_filter.service_error_filter: Refreshing state... [id=service-error-filter]
module.monitoring.aws_sns_topic.this: Refreshing state... [id=arn:aws:sns:us-east-1:315341936575:api-dev-monitoring]
module.service.data.aws_caller_identity.current: Read complete after 0s [id=315341936575]
module.service.data.aws_region.current: Reading...
module.service.data.aws_region.current: Read complete after 0s [id=us-east-1]
module.service.aws_s3_bucket.access_logs: Refreshing state... [id=api-dev-access-logs20231023213552646900000003]
data.aws_rds_cluster.db_cluster[0]: Read complete after 0s [id=api-dev]
module.service.data.aws_ecr_repository.app[0]: Reading...
data.terraform_remote_state.current_image_tag[0]: Read complete after 1s
module.service.aws_iam_role.app_service: Refreshing state... [id=api-dev-app]
module.service.aws_iam_role.task_executor: Refreshing state... [id=api-dev-task-executor]
module.service.aws_wafv2_web_acl.waf[0]: Refreshing state... [id=a13139a8-fb10-4545-89fb-924417495223]
module.service.data.aws_iam_policy_document.WafWebAclLoggingDoc[0]: Reading...
module.service.data.aws_iam_policy_document.WafWebAclLoggingDoc[0]: Read complete after 0s [id=919045586]
module.monitoring.aws_cloudwatch_metric_alarm.service_errors: Refreshing state... [id=api-dev-errors]
data.aws_vpc.network: Read complete after 1s [id=vpc-08f522c5cc442d126]
module.monitoring.aws_sns_topic_subscription.email_integration["grantsalerts@navapbc.com"]: Refreshing state... [id=arn:aws:sns:us-east-1:315341936575:api-dev-monitoring:4f5f4bcf-9458-464b-a675-17f6803695dc]
module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy[0]: Refreshing state... [id=service-api-dev-webacl-policy]
module.service.aws_iam_role.migrator_task[0]: Refreshing state... [id=api-dev-migrator]
data.aws_subnets.public: Reading...
data.aws_subnets.private: Reading...
data.aws_subnets.public: Read complete after 0s [id=us-east-1]
module.service.aws_security_group.alb: Refreshing state... [id=sg-025e1dd290c12d572]
module.service.aws_lb_target_group.app_tg[0]: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:targetgroup/app-20240129204404286300000001/2225bef73ea80162]
data.aws_subnets.private: Read complete after 0s [id=us-east-1]
module.service.aws_s3_bucket_public_access_block.general_purpose: Refreshing state... [id=api-dev-general-purpose20240416221336163000000001]
module.service.aws_s3_bucket_lifecycle_configuration.general_purpose: Refreshing state... [id=api-dev-general-purpose20240416221336163000000001]
module.service.data.aws_iam_policy_document.general_purpose_put_access: Reading...
module.service.data.aws_iam_policy_document.general_purpose_put_access: Read complete after 0s [id=612448226]
module.service.aws_s3_bucket_server_side_encryption_configuration.general_purpose_encryption: Refreshing state... [id=api-dev-general-purpose20240416221336163000000001]
module.service.data.aws_ecr_repository.app[0]: Read complete after 1s [id=simpler-grants-gov-api]
module.service.aws_s3_bucket_policy.general_purpose: Refreshing state... [id=api-dev-general-purpose20240416221336163000000001]
module.service.data.aws_iam_policy_document.task_executor: Reading...
module.service.data.aws_iam_policy_document.task_executor: Read complete after 0s [id=3249190051]
module.service.aws_security_group_rule.http_ingress: Refreshing state... [id=sgrule-69662097]
module.service.aws_security_group.app: Refreshing state... [id=sg-0eab49e76a34379f9]
module.service.aws_ecs_task_definition.app: Refreshing state... [id=api-dev]
module.service.aws_iam_role_policy.task_executor: Refreshing state... [id=api-dev-task-executor:api-dev-task-executor-role-policy]
module.service.aws_vpc_security_group_ingress_rule.db_ingress_from_service[0]: Refreshing state... [id=sgr-024fcce0dd2b24824]
aws_sfn_state_machine.copy_oracle_data: Refreshing state... [id=arn:aws:states:us-east-1:315341936575:stateMachine:api-dev-copy-oracle-data]
module.service.aws_s3_bucket_public_access_block.access_logs: Refreshing state... [id=api-dev-access-logs20231023213552646900000003]
module.service.aws_s3_bucket_server_side_encryption_configuration.encryption: Refreshing state... [id=api-dev-access-logs20231023213552646900000003]
module.service.data.aws_iam_policy_document.access_logs_put_access: Reading...
module.service.aws_s3_bucket_lifecycle_configuration.access_logs: Refreshing state... [id=api-dev-access-logs20231023213552646900000003]
module.service.data.aws_iam_policy_document.access_logs_put_access: Read complete after 0s [id=2049148182]
module.service.aws_s3_bucket_policy.access_logs: Refreshing state... [id=api-dev-access-logs20231023213552646900000003]
module.service.aws_ecs_service.app: Refreshing state... [id=arn:aws:ecs:us-east-1:315341936575:service/api-dev/api-dev]
data.aws_iam_policy.app_db_access_policy[0]: Read complete after 2s [id=arn:aws:iam::315341936575:policy/api-dev-app-access]
module.service.aws_iam_role_policy_attachment.app_service_db_access[0]: Refreshing state... [id=api-dev-app-20231023230412768300000001]
data.aws_iam_policy.migrator_db_access_policy[0]: Read complete after 2s [id=arn:aws:iam::315341936575:policy/api-dev-migrator-access]
module.service.aws_iam_role_policy_attachment.migrator_db_access[0]: Refreshing state... [id=api-dev-migrator-20231023230412789800000002]
module.service.aws_lb.alb[0]: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:loadbalancer/app/api-dev/48f2e65279b967a5]
aws_scheduler_schedule.copy_oracle_data: Refreshing state... [id=api-dev-copy-oracle-data/api-dev-copy-oracle-data]
module.service.aws_lb_listener.alb_listener_http[0]: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:listener/app/api-dev/48f2e65279b967a5/d4ce6505b9614ba0]
module.monitoring.aws_cloudwatch_metric_alarm.high_load_balancer_http_5xx_count: Refreshing state... [id=api-dev-high-load-balancer-5xx-count]
module.monitoring.aws_cloudwatch_metric_alarm.high_app_http_5xx_count: Refreshing state... [id=api-dev-high-app-5xx-count]
module.monitoring.aws_cloudwatch_metric_alarm.high_app_response_time: Refreshing state... [id=api-dev-high-app-response-time]
module.service.aws_lb_listener_rule.app_http_forward[0]: Refreshing state... [id=arn:aws:elasticloadbalancing:us-east-1:315341936575:listener-rule/app/api-dev/48f2e65279b967a5/d4ce6505b9614ba0/009594b77c825b5a]
module.service.aws_wafv2_web_acl_association.WafWebAclAssociation[0]: Refreshing state... [id=arn:aws:wafv2:us-east-1:315341936575:regional/webacl/api-dev-wafv2-web-acl/a13139a8-fb10-4545-89fb-924417495223,arn:aws:elasticloadbalancing:us-east-1:315341936575:loadbalancer/app/api-dev/48f2e65279b967a5]
module.service.aws_wafv2_web_acl_logging_configuration.WafWebAclLogging[0]: Refreshing state... [id=arn:aws:wafv2:us-east-1:315341936575:regional/webacl/api-dev-wafv2-web-acl/a13139a8-fb10-4545-89fb-924417495223]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # aws_sfn_state_machine.copy_oracle_data will be updated in-place
  ~ resource "aws_sfn_state_machine" "copy_oracle_data" {
      ~ definition                = jsonencode(
            {
              - StartAt = "ExecuteECSTask"
              - States  = {
                  - ExecuteECSTask = {
                      - End        = true
                      - Parameters = {
                          - Cluster              = "arn:aws:ecs:us-east-1:315341936575:cluster/api-dev"
                          - LaunchType           = "FARGATE"
                          - NetworkConfiguration = {
                              - AwsvpcConfiguration = {
                                  - SecurityGroups = [
                                      - "sg-0eab49e76a34379f9",
                                    ]
                                  - Subnets        = [
                                      - "subnet-0a5ea667d3751639f",
                                      - "subnet-068ede7dcfd9469ab",
                                      - "subnet-019f469ba97dc6ec7",
                                    ]
                                }
                            }
                          - Overrides            = {
                              - ContainerOverrides = [
                                  - {
                                      - Command     = [
                                          - "poetry",
                                          - "run",
                                          - "flask",
                                          - "data-migration",
                                          - "copy-oracle-data",
                                        ]
                                      - Environment = [
                                          - {
                                              - Name  = "FLASK_APP"
                                              - Value = "src.app:create_app()"
                                            },
                                        ]
                                      - Name        = "api-dev"
                                    },
                                ]
                            }
                          - TaskDefinition       = "arn:aws:ecs:us-east-1:315341936575:task-definition/api-dev:150"
                        }
                      - Resource   = "arn:aws:states:::ecs:runTask.sync"
                      - Type       = "Task"
                    }
                }
            }
        ) -> (known after apply)
        id                        = "arn:aws:states:us-east-1:315341936575:stateMachine:api-dev-copy-oracle-data"
        name                      = "api-dev-copy-oracle-data"
        tags                      = {}
        # (11 unchanged attributes hidden)

        # (2 unchanged blocks hidden)
    }

  # module.service.aws_cloudwatch_log_group.WafWebAclLoggroup has moved to module.service.aws_cloudwatch_log_group.WafWebAclLoggroup[0]
    resource "aws_cloudwatch_log_group" "WafWebAclLoggroup" {
        id                = "aws-waf-logs-wafv2-web-acl-api-dev"
        name              = "aws-waf-logs-wafv2-web-acl-api-dev"
        tags              = {}
        # (7 unchanged attributes hidden)
    }

  # module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy has moved to module.service.aws_cloudwatch_log_resource_policy.WafWebAclLoggingPolicy[0]
    resource "aws_cloudwatch_log_resource_policy" "WafWebAclLoggingPolicy" {
        id              = "service-api-dev-webacl-policy"
        # (2 unchanged attributes hidden)
    }

  # module.service.aws_ecs_service.app will be updated in-place
  ~ resource "aws_ecs_service" "app" {
        id                                 = "arn:aws:ecs:us-east-1:315341936575:service/api-dev/api-dev"
        name                               = "api-dev"
        tags                               = {}
      ~ task_definition                    = "arn:aws:ecs:us-east-1:315341936575:task-definition/api-dev:150" -> (known after apply)
        # (15 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.service.aws_ecs_task_definition.app must be replaced
-/+ resource "aws_ecs_task_definition" "app" {
      ~ arn                      = "arn:aws:ecs:us-east-1:315341936575:task-definition/api-dev:150" -> (known after apply)
      ~ arn_without_revision     = "arn:aws:ecs:us-east-1:315341936575:task-definition/api-dev" -> (known after apply)
      ~ container_definitions    = jsonencode(
          ~ [
              ~ {
                  ~ linuxParameters        = {
                      ~ capabilities       = {
                          - add  = []
                            # (1 unchanged attribute hidden)
                        }
                        # (1 unchanged attribute hidden)
                    }
                  - mountPoints            = []
                    name                   = "api-dev"
                  ~ portMappings           = [
                      ~ {
                          - hostPort      = 8000
                          - protocol      = "tcp"
                            # (1 unchanged attribute hidden)
                        },
                    ]
                  - systemControls         = []
                  - volumesFrom            = []
                    # (9 unchanged attributes hidden)
                },
            ] # forces replacement
        )
      ~ id                       = "api-dev" -> (known after apply)
      ~ revision                 = 150 -> (known after apply)
      - tags                     = {} -> null
        # (11 unchanged attributes hidden)
    }

  # module.service.aws_lb.alb has moved to module.service.aws_lb.alb[0]
    resource "aws_lb" "alb" {
        id                                                           = "arn:aws:elasticloadbalancing:us-east-1:315341936575:loadbalancer/app/api-dev/48f2e65279b967a5"
        name                                                         = "api-dev"
        tags                                                         = {}
        # (25 unchanged attributes hidden)

        # (5 unchanged blocks hidden)
    }

  # module.service.aws_lb_listener.alb_listener_http has moved to module.service.aws_lb_listener.alb_listener_http[0]
    resource "aws_lb_listener" "alb_listener_http" {
        id                = "arn:aws:elasticloadbalancing:us-east-1:315341936575:listener/app/api-dev/48f2e65279b967a5/d4ce6505b9614ba0"
        tags              = {}
        # (6 unchanged attributes hidden)

        # (1 unchanged block hidden)
    }

  # module.service.aws_lb_listener_rule.app_http_forward has moved to module.service.aws_lb_listener_rule.app_http_forward[0]
    resource "aws_lb_listener_rule" "app_http_forward" {
        id           = "arn:aws:elasticloadbalancing:us-east-1:315341936575:listener-rule/app/api-dev/48f2e65279b967a5/d4ce6505b9614ba0/009594b77c825b5a"
        tags         = {}
        # (4 unchanged attributes hidden)

        # (2 unchanged blocks hidden)
    }

  # module.service.aws_lb_target_group.app_tg has moved to module.service.aws_lb_target_group.app_tg[0]
    resource "aws_lb_target_group" "app_tg" {
        id                                 = "arn:aws:elasticloadbalancing:us-east-1:315341936575:targetgroup/app-20240129204404286300000001/2225bef73ea80162"
        name                               = "app-20240129204404286300000001"
        tags                               = {}
        # (18 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.service.aws_wafv2_web_acl.waf has moved to module.service.aws_wafv2_web_acl.waf[0]
    resource "aws_wafv2_web_acl" "waf" {
        id            = "a13139a8-fb10-4545-89fb-924417495223"
        name          = "api-dev-wafv2-web-acl"
        tags          = {}
        # (7 unchanged attributes hidden)

        # (9 unchanged blocks hidden)
    }

  # module.service.aws_wafv2_web_acl_association.WafWebAclAssociation has moved to module.service.aws_wafv2_web_acl_association.WafWebAclAssociation[0]
    resource "aws_wafv2_web_acl_association" "WafWebAclAssociation" {
        id           = "arn:aws:wafv2:us-east-1:315341936575:regional/webacl/api-dev-wafv2-web-acl/a13139a8-fb10-4545-89fb-924417495223,arn:aws:elasticloadbalancing:us-east-1:315341936575:loadbalancer/app/api-dev/48f2e65279b967a5"
        # (2 unchanged attributes hidden)
    }

  # module.service.aws_wafv2_web_acl_logging_configuration.WafWebAclLogging has moved to module.service.aws_wafv2_web_acl_logging_configuration.WafWebAclLogging[0]
    resource "aws_wafv2_web_acl_logging_configuration" "WafWebAclLogging" {
        id                      = "arn:aws:wafv2:us-east-1:315341936575:regional/webacl/api-dev-wafv2-web-acl/a13139a8-fb10-4545-89fb-924417495223"
        # (2 unchanged attributes hidden)
    }

Plan: 1 to add, 2 to change, 1 to destroy.

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

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
```

</details>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
project: grants.gov Grants.gov Modernization tickets refinement
Projects
Development

Successfully merging a pull request may close this issue.

2 participants