@ariestools/cli 0.1.16 → 0.1.18

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 +95560 -254131
  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 +10967 -4724
  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 +23 -20
@@ -368,10 +368,12 @@ function clearDefaultDatalake() {
368
368
  const filePath = getDefaultDatalakePath();
369
369
  if (existsSync(filePath)) unlinkSync(filePath);
370
370
  }
371
- function extractOrigin(urlWithPossiblePath) {
371
+ function extractRequestBase(urlWithPossiblePath) {
372
372
  try {
373
373
  const parsed = new URL(urlWithPossiblePath);
374
- return `${parsed.protocol}//${parsed.host}`;
374
+ const markerIndex = parsed.pathname.indexOf(`/v1/datalakes`);
375
+ const prefix = markerIndex === -1 ? parsed.pathname.replace(/\/$/, "") : parsed.pathname.slice(0, markerIndex);
376
+ return `${parsed.protocol}//${parsed.host}${prefix}`;
375
377
  } catch {
376
378
  return urlWithPossiblePath.replace(/\/$/, "");
377
379
  }
@@ -380,9 +382,9 @@ var RestPayloadsClient = class {
380
382
  authToken;
381
383
  datalakeId;
382
384
  fetchImpl;
383
- origin;
385
+ requestBase;
384
386
  constructor(options) {
385
- this.origin = extractOrigin(options.baseUrl);
387
+ this.requestBase = extractRequestBase(options.baseUrl);
386
388
  this.datalakeId = options.datalakeId;
387
389
  this.authToken = options.authToken;
388
390
  this.fetchImpl = options.fetchImpl ?? fetch;
@@ -451,7 +453,7 @@ var RestPayloadsClient = class {
451
453
  headers["content-type"] = "application/json";
452
454
  init.body = JSON.stringify(options.body);
453
455
  }
454
- const response = await this.fetchImpl(`${this.origin}${path4}`, init);
456
+ const response = await this.fetchImpl(`${this.requestBase}${path4}`, init);
455
457
  if (response.status === 204) return {
456
458
  data: void 0,
457
459
  headers: response.headers
@@ -0,0 +1,61 @@
1
+ resource "aws_security_group" "cluster" {
2
+ name = "${local.name_prefix}-cluster"
3
+ description = "EKS cluster control-plane SG"
4
+ vpc_id = aws_vpc.main.id
5
+
6
+ egress {
7
+ description = "All egress"
8
+ from_port = 0
9
+ to_port = 0
10
+ protocol = "-1"
11
+ cidr_blocks = ["0.0.0.0/0"]
12
+ }
13
+
14
+ tags = { Name = "${local.name_prefix}-cluster-sg" }
15
+ }
16
+
17
+ resource "aws_eks_cluster" "main" {
18
+ name = local.cluster_name
19
+ version = var.k8s_version
20
+ role_arn = aws_iam_role.cluster.arn
21
+
22
+ vpc_config {
23
+ subnet_ids = concat(
24
+ [for s in aws_subnet.public : s.id],
25
+ [for s in aws_subnet.private : s.id],
26
+ )
27
+ endpoint_public_access = var.endpoint_public_access
28
+ endpoint_private_access = true
29
+ public_access_cidrs = var.endpoint_public_access_cidrs
30
+ security_group_ids = [aws_security_group.cluster.id]
31
+ }
32
+
33
+ # Plug control-plane logs into CloudWatch so the SRE team isn't blind on day 1.
34
+ enabled_cluster_log_types = [
35
+ "api",
36
+ "audit",
37
+ "authenticator",
38
+ "controllerManager",
39
+ "scheduler",
40
+ ]
41
+
42
+ # EKS uses the cluster role + the worker node groups' instance profiles
43
+ # for default permissions. Additional access entries (e.g. promoting the
44
+ # human running `aries cluster aws up` to cluster admin) are wired below
45
+ # via aws_eks_access_entry / access_policy_association.
46
+
47
+ access_config {
48
+ authentication_mode = "API"
49
+ bootstrap_cluster_creator_admin_permissions = true
50
+ }
51
+
52
+ depends_on = [
53
+ aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy,
54
+ aws_iam_role_policy_attachment.cluster_AmazonEKSVPCResourceController,
55
+ ]
56
+ }
57
+
58
+ resource "aws_cloudwatch_log_group" "cluster" {
59
+ name = "/aws/eks/${local.cluster_name}/cluster"
60
+ retention_in_days = 30
61
+ }
@@ -0,0 +1,37 @@
1
+ # OpenTofu state encryption — opt-in.
2
+ #
3
+ # Encrypts `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
+ # - State encryption matters more here than in compute-aws because the
17
+ # EKS state file contains the cluster CA bundle and OIDC issuer URL.
18
+
19
+ terraform {
20
+ encryption {
21
+ key_provider "pbkdf2" "default" {
22
+ passphrase = var.tfstate_passphrase
23
+ }
24
+
25
+ method "aes_gcm" "default" {
26
+ keys = key_provider.pbkdf2.default
27
+ }
28
+
29
+ state {
30
+ method = method.aes_gcm.default
31
+ }
32
+
33
+ plan {
34
+ method = method.aes_gcm.default
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,81 @@
1
+ # --- EKS cluster role -------------------------------------------------------
2
+
3
+ data "aws_iam_policy_document" "cluster_assume" {
4
+ statement {
5
+ actions = ["sts:AssumeRole"]
6
+ principals {
7
+ type = "Service"
8
+ identifiers = ["eks.amazonaws.com"]
9
+ }
10
+ }
11
+ }
12
+
13
+ resource "aws_iam_role" "cluster" {
14
+ name = "${local.name_prefix}-cluster"
15
+ assume_role_policy = data.aws_iam_policy_document.cluster_assume.json
16
+ }
17
+
18
+ resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSClusterPolicy" {
19
+ role = aws_iam_role.cluster.name
20
+ policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
21
+ }
22
+
23
+ resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSVPCResourceController" {
24
+ role = aws_iam_role.cluster.name
25
+ policy_arn = "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController"
26
+ }
27
+
28
+ # --- Managed node group role ------------------------------------------------
29
+
30
+ data "aws_iam_policy_document" "node_assume" {
31
+ statement {
32
+ actions = ["sts:AssumeRole"]
33
+ principals {
34
+ type = "Service"
35
+ identifiers = ["ec2.amazonaws.com"]
36
+ }
37
+ }
38
+ }
39
+
40
+ resource "aws_iam_role" "node" {
41
+ name = "${local.name_prefix}-node"
42
+ assume_role_policy = data.aws_iam_policy_document.node_assume.json
43
+ }
44
+
45
+ resource "aws_iam_role_policy_attachment" "node_AmazonEKSWorkerNodePolicy" {
46
+ role = aws_iam_role.node.name
47
+ policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
48
+ }
49
+
50
+ resource "aws_iam_role_policy_attachment" "node_AmazonEKS_CNI_Policy" {
51
+ role = aws_iam_role.node.name
52
+ policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
53
+ }
54
+
55
+ resource "aws_iam_role_policy_attachment" "node_AmazonEC2ContainerRegistryReadOnly" {
56
+ role = aws_iam_role.node.name
57
+ policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
58
+ }
59
+
60
+ resource "aws_iam_role_policy_attachment" "node_AmazonSSMManagedInstanceCore" {
61
+ role = aws_iam_role.node.name
62
+ policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
63
+ }
64
+
65
+ # --- IRSA (IAM Roles for Service Accounts) ----------------------------------
66
+ #
67
+ # EKS exposes an OIDC issuer URL; pairing it with an IAM OIDC provider lets
68
+ # pods assume IAM roles via a service-account annotation. The service plane
69
+ # (service-datalake) uses this to grant the data-plane pod S3 access on the
70
+ # archive-tier bucket without storing AWS credentials anywhere.
71
+
72
+ data "tls_certificate" "cluster_oidc" {
73
+ url = aws_eks_cluster.main.identity[0].oidc[0].issuer
74
+ }
75
+
76
+ resource "aws_iam_openid_connect_provider" "cluster" {
77
+ url = aws_eks_cluster.main.identity[0].oidc[0].issuer
78
+ client_id_list = ["sts.amazonaws.com"]
79
+ thumbprint_list = [data.tls_certificate.cluster_oidc.certificates[0].sha1_fingerprint]
80
+ tags = { Name = "${local.name_prefix}-oidc" }
81
+ }
@@ -0,0 +1,37 @@
1
+ # IRSA role for the EBS CSI driver. The addon needs to attach EBS volumes
2
+ # to nodes (CreateVolume, AttachVolume, etc.) — those permissions belong
3
+ # to a per-cluster role tied to the cluster's OIDC issuer.
4
+ #
5
+ # Created here (not in service-datalake) because EBS CSI is cluster-level
6
+ # infra: PVCs of any kind require it. `aries cluster addons install`
7
+ # passes the role ARN below into `aws eks create-addon`.
8
+
9
+ data "aws_iam_policy_document" "ebs_csi_assume" {
10
+ statement {
11
+ actions = ["sts:AssumeRoleWithWebIdentity"]
12
+ principals {
13
+ type = "Federated"
14
+ identifiers = [aws_iam_openid_connect_provider.cluster.arn]
15
+ }
16
+ condition {
17
+ test = "StringEquals"
18
+ variable = "${replace(aws_iam_openid_connect_provider.cluster.url, "https://", "")}:sub"
19
+ values = ["system:serviceaccount:kube-system:ebs-csi-controller-sa"]
20
+ }
21
+ condition {
22
+ test = "StringEquals"
23
+ variable = "${replace(aws_iam_openid_connect_provider.cluster.url, "https://", "")}:aud"
24
+ values = ["sts.amazonaws.com"]
25
+ }
26
+ }
27
+ }
28
+
29
+ resource "aws_iam_role" "ebs_csi" {
30
+ name = "${local.name_prefix}-ebs-csi"
31
+ assume_role_policy = data.aws_iam_policy_document.ebs_csi_assume.json
32
+ }
33
+
34
+ resource "aws_iam_role_policy_attachment" "ebs_csi" {
35
+ role = aws_iam_role.ebs_csi.name
36
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"
37
+ }
@@ -0,0 +1,49 @@
1
+ # Render a standard EKS kubeconfig into the working dir. The `exec` block
2
+ # delegates auth to the user's local `aws` CLI (`aws eks get-token`), so
3
+ # the kubeconfig itself carries no long-lived secrets — perfect for
4
+ # checking in to ~/.aries/cluster/<name>/ alongside cluster.yaml.
5
+
6
+ locals {
7
+ kubeconfig_yaml = yamlencode({
8
+ apiVersion = "v1"
9
+ kind = "Config"
10
+ current-context = "aries-${local.cluster_name}"
11
+ clusters = [{
12
+ name = aws_eks_cluster.main.arn
13
+ cluster = {
14
+ server = aws_eks_cluster.main.endpoint
15
+ "certificate-authority-data" = aws_eks_cluster.main.certificate_authority[0].data
16
+ }
17
+ }]
18
+ contexts = [{
19
+ name = "aries-${local.cluster_name}"
20
+ context = {
21
+ cluster = aws_eks_cluster.main.arn
22
+ user = aws_eks_cluster.main.arn
23
+ }
24
+ }]
25
+ users = [{
26
+ name = aws_eks_cluster.main.arn
27
+ user = {
28
+ exec = {
29
+ apiVersion = "client.authentication.k8s.io/v1beta1"
30
+ command = "aws"
31
+ args = [
32
+ "--region", var.region,
33
+ "--profile", var.aws_profile,
34
+ "eks", "get-token",
35
+ "--cluster-name", local.cluster_name,
36
+ "--output", "json",
37
+ ]
38
+ }
39
+ }
40
+ }]
41
+ })
42
+ }
43
+
44
+ resource "local_sensitive_file" "kubeconfig" {
45
+ filename = "${path.cwd}/kubeconfig"
46
+ content = local.kubeconfig_yaml
47
+ file_permission = "0600"
48
+ directory_permission = "0700"
49
+ }
@@ -0,0 +1,108 @@
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
+ # Public subnets host the NAT gateway and external LBs (when the service
26
+ # plane installs ingress controllers later). EKS requires the
27
+ # `kubernetes.io/role/elb` tag for AWS Load Balancer Controller to pick
28
+ # the subnet for public ALBs/NLBs.
29
+ resource "aws_subnet" "public" {
30
+ for_each = { for i, az in local.azs : az => i }
31
+
32
+ vpc_id = aws_vpc.main.id
33
+ availability_zone = each.key
34
+ cidr_block = local.public_subnet_cidrs[each.value]
35
+ map_public_ip_on_launch = true
36
+
37
+ tags = {
38
+ Name = "${local.name_prefix}-public-${each.key}"
39
+ Tier = "public"
40
+ "kubernetes.io/role/elb" = "1"
41
+ "kubernetes.io/cluster/${local.cluster_name}" = "shared"
42
+ }
43
+ }
44
+
45
+ # Private subnets host the EKS managed node group + internal LBs. The
46
+ # `kubernetes.io/role/internal-elb` tag lets the LB controller place
47
+ # internal NLBs/ALBs here.
48
+ resource "aws_subnet" "private" {
49
+ for_each = { for i, az in local.azs : az => i }
50
+
51
+ vpc_id = aws_vpc.main.id
52
+ availability_zone = each.key
53
+ cidr_block = local.private_subnet_cidrs[each.value]
54
+
55
+ tags = {
56
+ Name = "${local.name_prefix}-private-${each.key}"
57
+ Tier = "private"
58
+ "kubernetes.io/role/internal-elb" = "1"
59
+ "kubernetes.io/cluster/${local.cluster_name}" = "shared"
60
+ }
61
+ }
62
+
63
+ resource "aws_eip" "nat" {
64
+ domain = "vpc"
65
+ tags = { Name = "${local.name_prefix}-nat" }
66
+ }
67
+
68
+ resource "aws_nat_gateway" "main" {
69
+ allocation_id = aws_eip.nat.id
70
+ subnet_id = aws_subnet.public[local.azs[0]].id
71
+
72
+ tags = { Name = "${local.name_prefix}-nat" }
73
+ depends_on = [aws_internet_gateway.main]
74
+ }
75
+
76
+ resource "aws_route_table" "public" {
77
+ vpc_id = aws_vpc.main.id
78
+
79
+ route {
80
+ cidr_block = "0.0.0.0/0"
81
+ gateway_id = aws_internet_gateway.main.id
82
+ }
83
+
84
+ tags = { Name = "${local.name_prefix}-public-rt" }
85
+ }
86
+
87
+ resource "aws_route_table" "private" {
88
+ vpc_id = aws_vpc.main.id
89
+
90
+ route {
91
+ cidr_block = "0.0.0.0/0"
92
+ nat_gateway_id = aws_nat_gateway.main.id
93
+ }
94
+
95
+ tags = { Name = "${local.name_prefix}-private-rt" }
96
+ }
97
+
98
+ resource "aws_route_table_association" "public" {
99
+ for_each = aws_subnet.public
100
+ subnet_id = each.value.id
101
+ route_table_id = aws_route_table.public.id
102
+ }
103
+
104
+ resource "aws_route_table_association" "private" {
105
+ for_each = aws_subnet.private
106
+ subnet_id = each.value.id
107
+ route_table_id = aws_route_table.private.id
108
+ }
@@ -0,0 +1,42 @@
1
+ resource "aws_eks_node_group" "default" {
2
+ cluster_name = aws_eks_cluster.main.name
3
+ node_group_name = "${local.cluster_name}-default"
4
+ node_role_arn = aws_iam_role.node.arn
5
+ subnet_ids = [for s in aws_subnet.private : s.id]
6
+
7
+ instance_types = var.node_instance_types
8
+ capacity_type = var.node_capacity_type
9
+ disk_size = var.node_disk_size_gb
10
+
11
+ scaling_config {
12
+ desired_size = var.node_desired_size
13
+ min_size = var.node_min_size
14
+ max_size = var.node_max_size
15
+ }
16
+
17
+ update_config {
18
+ max_unavailable_percentage = 33
19
+ }
20
+
21
+ # Default labels make it easy for Helm charts / NetworkPolicies to pin
22
+ # workloads to the shared pool. Phase 2b adds an `aries-tier=large`
23
+ # taint + dedicated node group for large-tier datalakes.
24
+ labels = {
25
+ "aries.xylabs.com/pool" = "shared"
26
+ }
27
+
28
+ tags = {
29
+ Name = "${local.cluster_name}-default"
30
+ }
31
+
32
+ depends_on = [
33
+ aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy,
34
+ aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy,
35
+ aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly,
36
+ aws_iam_role_policy_attachment.node_AmazonSSMManagedInstanceCore,
37
+ ]
38
+
39
+ lifecycle {
40
+ ignore_changes = [scaling_config[0].desired_size]
41
+ }
42
+ }
@@ -0,0 +1,80 @@
1
+ output "cluster_name" {
2
+ description = "EKS cluster name."
3
+ value = aws_eks_cluster.main.name
4
+ }
5
+
6
+ output "cluster_arn" {
7
+ description = "EKS cluster ARN."
8
+ value = aws_eks_cluster.main.arn
9
+ }
10
+
11
+ output "cluster_endpoint" {
12
+ description = "EKS API server endpoint."
13
+ value = aws_eks_cluster.main.endpoint
14
+ }
15
+
16
+ output "cluster_certificate_authority_data" {
17
+ description = "Base64-encoded cluster CA cert (for clients that don't use the rendered kubeconfig)."
18
+ value = aws_eks_cluster.main.certificate_authority[0].data
19
+ sensitive = true
20
+ }
21
+
22
+ output "oidc_provider_arn" {
23
+ description = "IAM OIDC provider ARN; bind workload IAM roles to this via IRSA."
24
+ value = aws_iam_openid_connect_provider.cluster.arn
25
+ }
26
+
27
+ output "oidc_provider_url" {
28
+ description = "OIDC issuer URL (without the leading `https://`) for IRSA trust policies."
29
+ value = replace(aws_eks_cluster.main.identity[0].oidc[0].issuer, "https://", "")
30
+ }
31
+
32
+ output "ebs_csi_role_arn" {
33
+ description = "IRSA role ARN for the EBS CSI driver addon. Pass to `aws eks create-addon --service-account-role-arn` so PVCs can attach EBS volumes."
34
+ value = aws_iam_role.ebs_csi.arn
35
+ }
36
+
37
+ output "vpc_id" {
38
+ description = "Dedicated VPC the cluster runs in."
39
+ value = aws_vpc.main.id
40
+ }
41
+
42
+ output "private_subnet_ids" {
43
+ description = "Subnets the managed node group runs in."
44
+ value = [for s in aws_subnet.private : s.id]
45
+ }
46
+
47
+ output "public_subnet_ids" {
48
+ description = "Public subnets (host NAT and external LBs)."
49
+ value = [for s in aws_subnet.public : s.id]
50
+ }
51
+
52
+ output "node_security_group_id" {
53
+ description = "Primary security group EKS attached to worker nodes."
54
+ value = aws_eks_cluster.main.vpc_config[0].cluster_security_group_id
55
+ }
56
+
57
+ output "kubeconfig_path" {
58
+ description = "Path to the rendered kubeconfig (relative to the working dir)."
59
+ value = local_sensitive_file.kubeconfig.filename
60
+ }
61
+
62
+ output "region" {
63
+ description = "AWS region the cluster lives in."
64
+ value = var.region
65
+ }
66
+
67
+ # The Tier-3 service plane reads this to construct its `ServiceTarget(kubernetes)`.
68
+ output "service_target" {
69
+ description = "Tier-2 → Tier-3 hand-off shape. The CLI projects this into ~/.aries/cluster/<name>/cluster.yaml."
70
+ value = {
71
+ kind = "kubernetes"
72
+ cloud = "aws"
73
+ cluster_name = aws_eks_cluster.main.name
74
+ region = var.region
75
+ namespace = "aries-datalake"
76
+ ingress_class = "nginx"
77
+ storage_class = "gp3"
78
+ kubeconfig = local_sensitive_file.kubeconfig.filename
79
+ }
80
+ }
@@ -0,0 +1,7 @@
1
+ provider "aws" {
2
+ region = var.region
3
+
4
+ default_tags {
5
+ tags = local.common_tags
6
+ }
7
+ }
@@ -0,0 +1,21 @@
1
+ region = "us-west-2"
2
+ aws_profile = "xylabs-datalake"
3
+ environment = "staging"
4
+ project = "aries-datalake"
5
+
6
+ # cluster_name defaults to `${project}-${environment}` when empty.
7
+ # cluster_name = "aries-datalake-staging"
8
+
9
+ # k8s_version = "1.31"
10
+
11
+ # vpc_cidr = "10.43.0.0/16" # must not overlap compute-aws (10.42.0.0/16)
12
+
13
+ # node_instance_types = ["t3.medium"]
14
+ # node_desired_size = 2
15
+ # node_min_size = 1
16
+ # node_max_size = 4
17
+ # node_capacity_type = "ON_DEMAND" # or "SPOT" for ~70% cheaper non-prod
18
+ # node_disk_size_gb = 50
19
+
20
+ # endpoint_public_access = true
21
+ # endpoint_public_access_cidrs = ["203.0.113.4/32"] # tighten to your office IP for prod
@@ -0,0 +1,120 @@
1
+ variable "region" {
2
+ type = string
3
+ description = "AWS region to deploy the EKS cluster into."
4
+ default = "us-west-2"
5
+ }
6
+
7
+ variable "aws_profile" {
8
+ type = string
9
+ description = "Local AWS CLI profile the IaC engine should use. Must already be configured via `aws configure` or `aws sso login`."
10
+ default = "xylabs-datalake"
11
+ }
12
+
13
+ variable "environment" {
14
+ type = string
15
+ description = "Environment name (staging, prod, etc.). Goes into resource tags + names."
16
+ default = "staging"
17
+ }
18
+
19
+ variable "project" {
20
+ type = string
21
+ description = "Project name; goes into resource tags."
22
+ default = "aries-datalake"
23
+ }
24
+
25
+ variable "cluster_name" {
26
+ type = string
27
+ description = "EKS cluster name. Defaults to `${var.project}-${var.environment}`."
28
+ default = ""
29
+ }
30
+
31
+ variable "k8s_version" {
32
+ type = string
33
+ description = "Kubernetes version for the EKS control plane."
34
+ default = "1.31"
35
+ }
36
+
37
+ variable "vpc_cidr" {
38
+ type = string
39
+ description = "CIDR block for the dedicated VPC. Must not overlap any existing VPC you intend to peer with — and must not overlap the compute-aws VPC if both stacks live in the same account."
40
+ default = "10.43.0.0/16"
41
+ }
42
+
43
+ variable "availability_zone_count" {
44
+ type = number
45
+ description = "Number of AZs to span (>= 2 required by EKS)."
46
+ default = 2
47
+ }
48
+
49
+ variable "node_instance_types" {
50
+ type = list(string)
51
+ description = "EC2 instance types for the managed node group. The first type is preferred; subsequent types are fallbacks when capacity is scarce."
52
+ default = ["t3.medium"]
53
+ }
54
+
55
+ variable "node_desired_size" {
56
+ type = number
57
+ description = "Desired number of worker nodes."
58
+ default = 2
59
+ }
60
+
61
+ variable "node_min_size" {
62
+ type = number
63
+ description = "Minimum number of worker nodes."
64
+ default = 1
65
+ }
66
+
67
+ variable "node_max_size" {
68
+ type = number
69
+ description = "Maximum number of worker nodes."
70
+ default = 4
71
+ }
72
+
73
+ variable "node_disk_size_gb" {
74
+ type = number
75
+ description = "Root EBS volume size per node."
76
+ default = 50
77
+ }
78
+
79
+ variable "node_capacity_type" {
80
+ type = string
81
+ description = "`ON_DEMAND` or `SPOT`. Spot is dramatically cheaper but EKS will replace nodes on reclamation."
82
+ default = "ON_DEMAND"
83
+ }
84
+
85
+ variable "endpoint_public_access" {
86
+ type = bool
87
+ description = "Whether the EKS API server is reachable from the public internet. Required for `aws eks update-kubeconfig` from a developer laptop. Phase 4 (PrivateLink) flips this to false."
88
+ default = true
89
+ }
90
+
91
+ variable "endpoint_public_access_cidrs" {
92
+ type = list(string)
93
+ description = "CIDRs allowed to reach the public EKS API endpoint. Defaults to anywhere; tighten to your office IP for prod."
94
+ default = ["0.0.0.0/0"]
95
+ }
96
+
97
+ variable "tfstate_passphrase" {
98
+ type = string
99
+ description = "Passphrase for OpenTofu state encryption. See encryption.tofu.example."
100
+ default = ""
101
+ sensitive = true
102
+ }
103
+
104
+ variable "scope_tags" {
105
+ type = map(string)
106
+ description = "Tags applied to every resource via the AWS provider's default_tags. Populated by the `aries compute add --infra ...` flow with the infra-uid + managed-by tag set; left empty when the legacy `aries cluster aws ...` commands invoke the module."
107
+ default = {}
108
+ }
109
+
110
+ locals {
111
+ cluster_name = length(var.cluster_name) > 0 ? var.cluster_name : "${var.project}-${var.environment}"
112
+ name_prefix = "${var.project}-${var.environment}-cluster"
113
+
114
+ common_tags = merge({
115
+ Project = var.project
116
+ Environment = var.environment
117
+ Component = "cluster"
118
+ ManagedBy = "opentofu"
119
+ }, var.scope_tags)
120
+ }