@ariestools/cli 0.1.16 → 0.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +51 -11
  2. package/dist/bin/aries.mjs +94138 -253208
  3. package/dist/bin/daemons/chain-server.mjs +9862 -12
  4. package/dist/bin/daemons/dapp-server.mjs +55 -56
  5. package/dist/bin/daemons/datalake-dev.mjs +10282 -4342
  6. package/dist/node/datalake.mjs +7 -5
  7. package/dist/terraform/cluster-aws/cluster.tf +61 -0
  8. package/dist/terraform/cluster-aws/encryption.tofu.example +37 -0
  9. package/dist/terraform/cluster-aws/iam.tf +81 -0
  10. package/dist/terraform/cluster-aws/irsa_ebs_csi.tf +37 -0
  11. package/dist/terraform/cluster-aws/kubeconfig.tf +49 -0
  12. package/dist/terraform/cluster-aws/network.tf +108 -0
  13. package/dist/terraform/cluster-aws/nodegroup.tf +42 -0
  14. package/dist/terraform/cluster-aws/outputs.tf +80 -0
  15. package/dist/terraform/cluster-aws/providers.tf +7 -0
  16. package/dist/terraform/cluster-aws/terraform.tfvars.example +21 -0
  17. package/dist/terraform/cluster-aws/variables.tf +120 -0
  18. package/dist/terraform/cluster-aws/versions.tf +18 -0
  19. package/dist/terraform/cluster-azure/cluster.tf +83 -0
  20. package/dist/terraform/cluster-azure/encryption.tofu.example +37 -0
  21. package/dist/terraform/cluster-azure/identity.tf +9 -0
  22. package/dist/terraform/cluster-azure/kubeconfig.tf +18 -0
  23. package/dist/terraform/cluster-azure/network.tf +23 -0
  24. package/dist/terraform/cluster-azure/outputs.tf +69 -0
  25. package/dist/terraform/cluster-azure/providers.tf +16 -0
  26. package/dist/terraform/cluster-azure/terraform.tfvars.example +24 -0
  27. package/dist/terraform/cluster-azure/variables.tf +126 -0
  28. package/dist/terraform/cluster-azure/versions.tf +14 -0
  29. package/dist/terraform/cluster-gcp/cluster.tf +71 -0
  30. package/dist/terraform/cluster-gcp/encryption.tofu.example +35 -0
  31. package/dist/terraform/cluster-gcp/kubeconfig.tf +47 -0
  32. package/dist/terraform/cluster-gcp/network.tf +47 -0
  33. package/dist/terraform/cluster-gcp/outputs.tf +70 -0
  34. package/dist/terraform/cluster-gcp/providers.tf +14 -0
  35. package/dist/terraform/cluster-gcp/terraform.tfvars.example +17 -0
  36. package/dist/terraform/cluster-gcp/variables.tf +86 -0
  37. package/dist/terraform/cluster-gcp/versions.tf +14 -0
  38. package/dist/terraform/serverless-aws/alb.tf +127 -0
  39. package/dist/terraform/serverless-aws/database.tf +70 -0
  40. package/dist/terraform/serverless-aws/dns.tf +80 -0
  41. package/dist/terraform/serverless-aws/ecr.tf +63 -0
  42. package/dist/terraform/serverless-aws/ecs.tf +199 -0
  43. package/dist/terraform/serverless-aws/encryption.tofu.example +38 -0
  44. package/dist/terraform/serverless-aws/iam.tf +68 -0
  45. package/dist/terraform/serverless-aws/network.tf +190 -0
  46. package/dist/terraform/serverless-aws/outputs.tf +64 -0
  47. package/dist/terraform/serverless-aws/providers.tf +19 -0
  48. package/dist/terraform/serverless-aws/storage.tf +51 -0
  49. package/dist/terraform/serverless-aws/terraform.tfvars.example +19 -0
  50. package/dist/terraform/serverless-aws/variables.tf +151 -0
  51. package/dist/terraform/serverless-aws/versions.tf +14 -0
  52. package/package.json +22 -19
@@ -0,0 +1,199 @@
1
+ resource "aws_ecs_cluster" "main" {
2
+ name = "${local.name_prefix}-cluster"
3
+
4
+ setting {
5
+ name = "containerInsights"
6
+ value = "enabled"
7
+ }
8
+ }
9
+
10
+ resource "aws_cloudwatch_log_group" "control" {
11
+ name = "/aws/ecs/${local.name_prefix}-control"
12
+ retention_in_days = 30
13
+ }
14
+
15
+ resource "aws_cloudwatch_log_group" "plane" {
16
+ name = "/aws/ecs/${local.name_prefix}-plane"
17
+ retention_in_days = 30
18
+ }
19
+
20
+ locals {
21
+ # When ECR repos are created in-stack (legacy flow), fall back to a `:bootstrap`
22
+ # tag against the local repo URI if the caller didn't set var.control_image yet.
23
+ # When ECR repos are owned by `aries infra images` instead (new flow), the caller
24
+ # MUST set var.control_image / var.plane_image — empty falls through and Fargate
25
+ # will refuse to launch a task with no image.
26
+ control_image = (
27
+ length(var.control_image) > 0 ? var.control_image :
28
+ var.create_ecr_repos ? "${aws_ecr_repository.control[0].repository_url}:bootstrap" :
29
+ ""
30
+ )
31
+ plane_image = (
32
+ length(var.plane_image) > 0 ? var.plane_image :
33
+ var.create_ecr_repos ? "${aws_ecr_repository.plane[0].repository_url}:bootstrap" :
34
+ ""
35
+ )
36
+
37
+ control_origin_url = local.has_domain ? "https://${local.data_fqdn}" : "http://${aws_lb.main.dns_name}/plane"
38
+ }
39
+
40
+ resource "aws_ecs_task_definition" "control" {
41
+ family = "${local.name_prefix}-control"
42
+ cpu = var.control_task_cpu
43
+ memory = var.control_task_memory
44
+ network_mode = "awsvpc"
45
+ requires_compatibilities = ["FARGATE"]
46
+ execution_role_arn = aws_iam_role.task_execution.arn
47
+ task_role_arn = aws_iam_role.control_task.arn
48
+
49
+ runtime_platform {
50
+ operating_system_family = "LINUX"
51
+ cpu_architecture = "ARM64"
52
+ }
53
+
54
+ container_definitions = jsonencode([{
55
+ name = "control"
56
+ image = local.control_image
57
+ essential = true
58
+
59
+ portMappings = [{
60
+ containerPort = 8787
61
+ protocol = "tcp"
62
+ }]
63
+
64
+ environment = [
65
+ { name = "STORE", value = "postgres" },
66
+ { name = "PORT", value = "8787" },
67
+ { name = "HOST", value = "0.0.0.0" },
68
+ { name = "DATALAKE_ORIGIN_URL", value = local.control_origin_url },
69
+ { name = "LOG_LEVEL", value = "info" },
70
+ { name = "CONTROL_VERSION", value = "0.1.0" },
71
+ ]
72
+
73
+ secrets = [
74
+ { name = "DATABASE_URL", valueFrom = aws_secretsmanager_secret.database_url.arn },
75
+ { name = "TOKEN_SIGNING_SECRET", valueFrom = aws_secretsmanager_secret.token_signing.arn },
76
+ ]
77
+
78
+ logConfiguration = {
79
+ logDriver = "awslogs"
80
+ options = {
81
+ "awslogs-group" = aws_cloudwatch_log_group.control.name
82
+ "awslogs-region" = var.region
83
+ "awslogs-stream-prefix" = "control"
84
+ }
85
+ }
86
+ }])
87
+ }
88
+
89
+ resource "aws_ecs_task_definition" "plane" {
90
+ family = "${local.name_prefix}-plane"
91
+ cpu = var.plane_task_cpu
92
+ memory = var.plane_task_memory
93
+ network_mode = "awsvpc"
94
+ requires_compatibilities = ["FARGATE"]
95
+ execution_role_arn = aws_iam_role.task_execution.arn
96
+ task_role_arn = aws_iam_role.plane_task.arn
97
+
98
+ runtime_platform {
99
+ operating_system_family = "LINUX"
100
+ cpu_architecture = "ARM64"
101
+ }
102
+
103
+ container_definitions = jsonencode([{
104
+ name = "plane"
105
+ image = local.plane_image
106
+ essential = true
107
+
108
+ portMappings = [{
109
+ containerPort = 8788
110
+ protocol = "tcp"
111
+ }]
112
+
113
+ environment = [
114
+ { name = "CONTROL_STORE", value = "postgres" },
115
+ { name = "PAYLOAD_STORE", value = "postgres" },
116
+ { name = "PORT", value = "8788" },
117
+ { name = "HOST", value = "0.0.0.0" },
118
+ { name = "AWS_REGION", value = var.region },
119
+ { name = "PAYLOAD_S3_BUCKET", value = aws_s3_bucket.payloads.bucket },
120
+ { name = "DATALAKE_ROUTE_PREFIX", value = local.has_domain ? "" : "/plane" },
121
+ { name = "LOG_LEVEL", value = "info" },
122
+ { name = "PLANE_VERSION", value = "0.1.0" },
123
+ ]
124
+
125
+ secrets = [
126
+ { name = "DATABASE_URL", valueFrom = aws_secretsmanager_secret.database_url.arn },
127
+ { name = "TOKEN_SIGNING_SECRET", valueFrom = aws_secretsmanager_secret.token_signing.arn },
128
+ ]
129
+
130
+ logConfiguration = {
131
+ logDriver = "awslogs"
132
+ options = {
133
+ "awslogs-group" = aws_cloudwatch_log_group.plane.name
134
+ "awslogs-region" = var.region
135
+ "awslogs-stream-prefix" = "plane"
136
+ }
137
+ }
138
+ }])
139
+ }
140
+
141
+ resource "aws_ecs_service" "control" {
142
+ name = "${local.name_prefix}-control"
143
+ cluster = aws_ecs_cluster.main.id
144
+ task_definition = aws_ecs_task_definition.control.arn
145
+ desired_count = var.control_desired_count
146
+ launch_type = "FARGATE"
147
+ propagate_tags = "SERVICE"
148
+
149
+ network_configuration {
150
+ subnets = [for s in aws_subnet.private : s.id]
151
+ security_groups = [aws_security_group.service.id]
152
+ assign_public_ip = false
153
+ }
154
+
155
+ load_balancer {
156
+ target_group_arn = aws_lb_target_group.control.arn
157
+ container_name = "control"
158
+ container_port = 8787
159
+ }
160
+
161
+ deployment_minimum_healthy_percent = 50
162
+ deployment_maximum_percent = 200
163
+
164
+ lifecycle {
165
+ ignore_changes = [desired_count]
166
+ }
167
+
168
+ depends_on = [aws_lb_listener.http]
169
+ }
170
+
171
+ resource "aws_ecs_service" "plane" {
172
+ name = "${local.name_prefix}-plane"
173
+ cluster = aws_ecs_cluster.main.id
174
+ task_definition = aws_ecs_task_definition.plane.arn
175
+ desired_count = var.plane_desired_count
176
+ launch_type = "FARGATE"
177
+ propagate_tags = "SERVICE"
178
+
179
+ network_configuration {
180
+ subnets = [for s in aws_subnet.private : s.id]
181
+ security_groups = [aws_security_group.service.id]
182
+ assign_public_ip = false
183
+ }
184
+
185
+ load_balancer {
186
+ target_group_arn = aws_lb_target_group.plane.arn
187
+ container_name = "plane"
188
+ container_port = 8788
189
+ }
190
+
191
+ deployment_minimum_healthy_percent = 50
192
+ deployment_maximum_percent = 200
193
+
194
+ lifecycle {
195
+ ignore_changes = [desired_count]
196
+ }
197
+
198
+ depends_on = [aws_lb_listener.http]
199
+ }
@@ -0,0 +1,38 @@
1
+ # OpenTofu state encryption — opt-in.
2
+ #
3
+ # Encrypts both `terraform.tfstate` and any saved plan files at rest using
4
+ # AES-GCM with a key derived from `var.tfstate_passphrase` via PBKDF2.
5
+ #
6
+ # To enable:
7
+ # 1. cp encryption.tofu.example encryption.tofu (in the working dir)
8
+ # 2. export TF_VAR_tfstate_passphrase='at-least-16-characters'
9
+ # 3. tofu init -reconfigure
10
+ #
11
+ # Notes:
12
+ # - This file uses the `.tofu` extension so Terraform does NOT load it.
13
+ # Only OpenTofu engages encryption. Terraform users skip this block.
14
+ # - If you lose the passphrase, the state is unrecoverable — keep it in
15
+ # a password manager / Secrets Manager / etc.
16
+ # - To rotate the passphrase: add a second `key_provider` block with
17
+ # the old passphrase, set it as `fallback`, then `tofu apply` to
18
+ # re-encrypt with the new key. Drop the fallback once migrated.
19
+
20
+ terraform {
21
+ encryption {
22
+ key_provider "pbkdf2" "default" {
23
+ passphrase = var.tfstate_passphrase
24
+ }
25
+
26
+ method "aes_gcm" "default" {
27
+ keys = key_provider.pbkdf2.default
28
+ }
29
+
30
+ state {
31
+ method = method.aes_gcm.default
32
+ }
33
+
34
+ plan {
35
+ method = method.aes_gcm.default
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,68 @@
1
+ data "aws_iam_policy_document" "ecs_task_assume" {
2
+ statement {
3
+ actions = ["sts:AssumeRole"]
4
+ principals {
5
+ type = "Service"
6
+ identifiers = ["ecs-tasks.amazonaws.com"]
7
+ }
8
+ }
9
+ }
10
+
11
+ resource "aws_iam_role" "task_execution" {
12
+ name = "${local.name_prefix}-task-execution"
13
+ assume_role_policy = data.aws_iam_policy_document.ecs_task_assume.json
14
+ }
15
+
16
+ resource "aws_iam_role_policy_attachment" "task_execution_basic" {
17
+ role = aws_iam_role.task_execution.name
18
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
19
+ }
20
+
21
+ data "aws_iam_policy_document" "task_execution_secrets" {
22
+ statement {
23
+ actions = ["secretsmanager:GetSecretValue"]
24
+ resources = [
25
+ aws_secretsmanager_secret.database_url.arn,
26
+ aws_secretsmanager_secret.token_signing.arn,
27
+ ]
28
+ }
29
+ }
30
+
31
+ resource "aws_iam_role_policy" "task_execution_secrets" {
32
+ name = "${local.name_prefix}-task-execution-secrets"
33
+ role = aws_iam_role.task_execution.id
34
+ policy = data.aws_iam_policy_document.task_execution_secrets.json
35
+ }
36
+
37
+ # Task role: scoped to the service's runtime needs. Plane needs S3 rw on the
38
+ # payloads bucket; control plane currently needs nothing beyond logs.
39
+ resource "aws_iam_role" "control_task" {
40
+ name = "${local.name_prefix}-control-task"
41
+ assume_role_policy = data.aws_iam_policy_document.ecs_task_assume.json
42
+ }
43
+
44
+ resource "aws_iam_role" "plane_task" {
45
+ name = "${local.name_prefix}-plane-task"
46
+ assume_role_policy = data.aws_iam_policy_document.ecs_task_assume.json
47
+ }
48
+
49
+ data "aws_iam_policy_document" "plane_s3" {
50
+ statement {
51
+ actions = [
52
+ "s3:GetObject",
53
+ "s3:PutObject",
54
+ "s3:DeleteObject",
55
+ "s3:ListBucket",
56
+ ]
57
+ resources = [
58
+ aws_s3_bucket.payloads.arn,
59
+ "${aws_s3_bucket.payloads.arn}/*",
60
+ ]
61
+ }
62
+ }
63
+
64
+ resource "aws_iam_role_policy" "plane_s3" {
65
+ name = "${local.name_prefix}-plane-s3"
66
+ role = aws_iam_role.plane_task.id
67
+ policy = data.aws_iam_policy_document.plane_s3.json
68
+ }
@@ -0,0 +1,190 @@
1
+ data "aws_availability_zones" "available" {
2
+ state = "available"
3
+ }
4
+
5
+ locals {
6
+ azs = slice(data.aws_availability_zones.available.names, 0, var.availability_zone_count)
7
+
8
+ public_subnet_cidrs = [for i, _ in local.azs : cidrsubnet(var.vpc_cidr, 8, i)]
9
+ private_subnet_cidrs = [for i, _ in local.azs : cidrsubnet(var.vpc_cidr, 8, i + 16)]
10
+ }
11
+
12
+ resource "aws_vpc" "main" {
13
+ cidr_block = var.vpc_cidr
14
+ enable_dns_support = true
15
+ enable_dns_hostnames = true
16
+
17
+ tags = { Name = "${local.name_prefix}-vpc" }
18
+ }
19
+
20
+ resource "aws_internet_gateway" "main" {
21
+ vpc_id = aws_vpc.main.id
22
+ tags = { Name = "${local.name_prefix}-igw" }
23
+ }
24
+
25
+ resource "aws_subnet" "public" {
26
+ for_each = { for i, az in local.azs : az => i }
27
+
28
+ vpc_id = aws_vpc.main.id
29
+ availability_zone = each.key
30
+ cidr_block = local.public_subnet_cidrs[each.value]
31
+ map_public_ip_on_launch = true
32
+
33
+ tags = {
34
+ Name = "${local.name_prefix}-public-${each.key}"
35
+ Tier = "public"
36
+ }
37
+ }
38
+
39
+ resource "aws_subnet" "private" {
40
+ for_each = { for i, az in local.azs : az => i }
41
+
42
+ vpc_id = aws_vpc.main.id
43
+ availability_zone = each.key
44
+ cidr_block = local.private_subnet_cidrs[each.value]
45
+
46
+ tags = {
47
+ Name = "${local.name_prefix}-private-${each.key}"
48
+ Tier = "private"
49
+ }
50
+ }
51
+
52
+ resource "aws_eip" "nat" {
53
+ domain = "vpc"
54
+ tags = { Name = "${local.name_prefix}-nat" }
55
+ }
56
+
57
+ resource "aws_nat_gateway" "main" {
58
+ allocation_id = aws_eip.nat.id
59
+ subnet_id = aws_subnet.public[local.azs[0]].id
60
+
61
+ tags = { Name = "${local.name_prefix}-nat" }
62
+ depends_on = [aws_internet_gateway.main]
63
+ }
64
+
65
+ resource "aws_route_table" "public" {
66
+ vpc_id = aws_vpc.main.id
67
+
68
+ route {
69
+ cidr_block = "0.0.0.0/0"
70
+ gateway_id = aws_internet_gateway.main.id
71
+ }
72
+
73
+ tags = { Name = "${local.name_prefix}-public-rt" }
74
+ }
75
+
76
+ resource "aws_route_table" "private" {
77
+ vpc_id = aws_vpc.main.id
78
+
79
+ route {
80
+ cidr_block = "0.0.0.0/0"
81
+ nat_gateway_id = aws_nat_gateway.main.id
82
+ }
83
+
84
+ tags = { Name = "${local.name_prefix}-private-rt" }
85
+ }
86
+
87
+ resource "aws_route_table_association" "public" {
88
+ for_each = aws_subnet.public
89
+ subnet_id = each.value.id
90
+ route_table_id = aws_route_table.public.id
91
+ }
92
+
93
+ resource "aws_route_table_association" "private" {
94
+ for_each = aws_subnet.private
95
+ subnet_id = each.value.id
96
+ route_table_id = aws_route_table.private.id
97
+ }
98
+
99
+ # --- security groups -------------------------------------------------------
100
+
101
+ resource "aws_security_group" "alb" {
102
+ name = "${local.name_prefix}-alb"
103
+ description = "Internet-facing ingress for the ALB"
104
+ vpc_id = aws_vpc.main.id
105
+
106
+ ingress {
107
+ description = "HTTPS from anywhere"
108
+ from_port = 443
109
+ to_port = 443
110
+ protocol = "tcp"
111
+ cidr_blocks = ["0.0.0.0/0"]
112
+ }
113
+
114
+ ingress {
115
+ description = "HTTP from anywhere (redirected to HTTPS at the listener)"
116
+ from_port = 80
117
+ to_port = 80
118
+ protocol = "tcp"
119
+ cidr_blocks = ["0.0.0.0/0"]
120
+ }
121
+
122
+ egress {
123
+ description = "Outbound to anywhere (ALB to Fargate tasks)"
124
+ from_port = 0
125
+ to_port = 0
126
+ protocol = "-1"
127
+ cidr_blocks = ["0.0.0.0/0"]
128
+ }
129
+
130
+ tags = { Name = "${local.name_prefix}-alb-sg" }
131
+ }
132
+
133
+ resource "aws_security_group" "service" {
134
+ name = "${local.name_prefix}-service"
135
+ description = "Fargate tasks; only accepts traffic from the ALB"
136
+ vpc_id = aws_vpc.main.id
137
+
138
+ egress {
139
+ description = "Egress to the internet via NAT (ECR pulls, third-party APIs)"
140
+ from_port = 0
141
+ to_port = 0
142
+ protocol = "-1"
143
+ cidr_blocks = ["0.0.0.0/0"]
144
+ }
145
+
146
+ tags = { Name = "${local.name_prefix}-service-sg" }
147
+ }
148
+
149
+ resource "aws_security_group_rule" "service_from_alb_8787" {
150
+ type = "ingress"
151
+ from_port = 8787
152
+ to_port = 8787
153
+ protocol = "tcp"
154
+ source_security_group_id = aws_security_group.alb.id
155
+ security_group_id = aws_security_group.service.id
156
+ description = "Control plane from ALB"
157
+ }
158
+
159
+ resource "aws_security_group_rule" "service_from_alb_8788" {
160
+ type = "ingress"
161
+ from_port = 8788
162
+ to_port = 8788
163
+ protocol = "tcp"
164
+ source_security_group_id = aws_security_group.alb.id
165
+ security_group_id = aws_security_group.service.id
166
+ description = "Data plane from ALB"
167
+ }
168
+
169
+ resource "aws_security_group" "database" {
170
+ name = "${local.name_prefix}-db"
171
+ description = "RDS Postgres; only accepts traffic from the Fargate service SG"
172
+ vpc_id = aws_vpc.main.id
173
+
174
+ ingress {
175
+ description = "Postgres from Fargate tasks"
176
+ from_port = 5432
177
+ to_port = 5432
178
+ protocol = "tcp"
179
+ security_groups = [aws_security_group.service.id]
180
+ }
181
+
182
+ egress {
183
+ from_port = 0
184
+ to_port = 0
185
+ protocol = "-1"
186
+ cidr_blocks = ["0.0.0.0/0"]
187
+ }
188
+
189
+ tags = { Name = "${local.name_prefix}-db-sg" }
190
+ }
@@ -0,0 +1,64 @@
1
+ output "alb_dns_name" {
2
+ description = "Public DNS of the ALB. Use this when `domain_name` is empty."
3
+ value = aws_lb.main.dns_name
4
+ }
5
+
6
+ output "api_url" {
7
+ description = "Control plane URL. When `domain_name` is set, https://api.<domain>; otherwise the ALB DNS over HTTP."
8
+ value = local.has_domain ? "https://${local.api_fqdn}" : "http://${aws_lb.main.dns_name}"
9
+ }
10
+
11
+ output "data_url" {
12
+ description = "Data plane URL. When `domain_name` is set, https://data.<domain>; otherwise the ALB DNS with /plane path prefix."
13
+ value = local.has_domain ? "https://${local.data_fqdn}" : "http://${aws_lb.main.dns_name}/plane"
14
+ }
15
+
16
+ output "ecr_control_repository" {
17
+ description = "ECR repository URI for the control plane image. Empty when the stack does not own its ECR (create_ecr_repos=false)."
18
+ value = var.create_ecr_repos ? aws_ecr_repository.control[0].repository_url : ""
19
+ }
20
+
21
+ output "ecr_plane_repository" {
22
+ description = "ECR repository URI for the data plane image. Empty when the stack does not own its ECR (create_ecr_repos=false)."
23
+ value = var.create_ecr_repos ? aws_ecr_repository.plane[0].repository_url : ""
24
+ }
25
+
26
+ output "rds_endpoint" {
27
+ description = "RDS Postgres host (internal to the VPC; not publicly reachable)."
28
+ value = aws_db_instance.main.address
29
+ }
30
+
31
+ output "payloads_bucket" {
32
+ description = "S3 bucket holding archive-tier payloads."
33
+ value = aws_s3_bucket.payloads.bucket
34
+ }
35
+
36
+ output "vpc_id" {
37
+ description = "Dedicated VPC id."
38
+ value = aws_vpc.main.id
39
+ }
40
+
41
+ output "ecs_cluster_name" {
42
+ description = "ECS cluster name used for live status checks."
43
+ value = aws_ecs_cluster.main.name
44
+ }
45
+
46
+ output "control_service_name" {
47
+ description = "Control-plane ECS service name used for live status checks."
48
+ value = aws_ecs_service.control.name
49
+ }
50
+
51
+ output "plane_service_name" {
52
+ description = "Data-plane ECS service name used for live status checks."
53
+ value = aws_ecs_service.plane.name
54
+ }
55
+
56
+ output "database_url_secret_arn" {
57
+ description = "Secrets Manager ARN containing the Postgres connection string."
58
+ value = aws_secretsmanager_secret.database_url.arn
59
+ }
60
+
61
+ output "token_signing_secret_arn" {
62
+ description = "Secrets Manager ARN for the HMAC signing secret shared by both planes."
63
+ value = aws_secretsmanager_secret.token_signing.arn
64
+ }
@@ -0,0 +1,19 @@
1
+ provider "aws" {
2
+ region = var.region
3
+
4
+ default_tags {
5
+ tags = local.common_tags
6
+ }
7
+ }
8
+
9
+ # us-east-1 is required for ACM certificates fronting CloudFront. We do not
10
+ # use CloudFront in phase 1 but keep this aliased provider available so phase
11
+ # 5 (multi-region + edge router) can attach without restructuring providers.
12
+ provider "aws" {
13
+ alias = "us_east_1"
14
+ region = "us-east-1"
15
+
16
+ default_tags {
17
+ tags = local.common_tags
18
+ }
19
+ }
@@ -0,0 +1,51 @@
1
+ resource "aws_s3_bucket" "payloads" {
2
+ bucket = "${local.name_prefix}-payloads-${data.aws_caller_identity.current.account_id}-${var.region}"
3
+ force_destroy = var.environment != "prod"
4
+ }
5
+
6
+ resource "aws_s3_bucket_public_access_block" "payloads" {
7
+ bucket = aws_s3_bucket.payloads.id
8
+
9
+ block_public_acls = true
10
+ block_public_policy = true
11
+ ignore_public_acls = true
12
+ restrict_public_buckets = true
13
+ }
14
+
15
+ resource "aws_s3_bucket_server_side_encryption_configuration" "payloads" {
16
+ bucket = aws_s3_bucket.payloads.id
17
+
18
+ rule {
19
+ apply_server_side_encryption_by_default {
20
+ sse_algorithm = "AES256"
21
+ }
22
+ }
23
+ }
24
+
25
+ resource "aws_s3_bucket_versioning" "payloads" {
26
+ bucket = aws_s3_bucket.payloads.id
27
+ versioning_configuration {
28
+ status = "Enabled"
29
+ }
30
+ }
31
+
32
+ resource "aws_s3_bucket_lifecycle_configuration" "payloads" {
33
+ bucket = aws_s3_bucket.payloads.id
34
+
35
+ rule {
36
+ id = "expire-old-versions"
37
+ status = "Enabled"
38
+
39
+ filter {}
40
+
41
+ noncurrent_version_expiration {
42
+ noncurrent_days = 30
43
+ }
44
+
45
+ abort_incomplete_multipart_upload {
46
+ days_after_initiation = 7
47
+ }
48
+ }
49
+ }
50
+
51
+ data "aws_caller_identity" "current" {}
@@ -0,0 +1,19 @@
1
+ region = "us-west-2"
2
+ aws_profile = "xylabs-datalake"
3
+ environment = "staging"
4
+ project = "aries-datalake"
5
+
6
+ # A major-version prefix selects the latest matching version offered in the region.
7
+ db_engine_version = "16"
8
+
9
+ # Set this to your domain when you're ready to put real DNS in front of the
10
+ # stack. Until then leave it empty and reach the ALB over its AWS DNS name.
11
+ # domain_name = "datalake.xylabs.com"
12
+ # create_route53_zone = false # set true if OpenTofu should create the zone
13
+
14
+ # Set these after `docker push` runs against the ECR repos that this stack
15
+ # creates. On the very first `terraform apply` leave them at their defaults;
16
+ # OpenTofu will provision the repos with a placeholder image tag, and you
17
+ # then push real images and re-apply to pick them up.
18
+ # control_image = "123456789012.dkr.ecr.us-west-2.amazonaws.com/aries-datalake-staging-control:0.1.0"
19
+ # plane_image = "123456789012.dkr.ecr.us-west-2.amazonaws.com/aries-datalake-staging-plane:0.1.0"