Skip to content

Commit 5b60a2e

Browse files
committed
feat: Add s3_outputs module to write shared values.
1 parent 807e562 commit 5b60a2e

File tree

10 files changed

+302
-0
lines changed

10 files changed

+302
-0
lines changed

modules/controlplane_rift/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ output "tecton" {
7272
| <a name="output_cross_account_role_arn"></a> [cross\_account\_role\_arn](#output\_cross\_account\_role\_arn) | n/a |
7373
| <a name="output_deployment_name"></a> [deployment\_name](#output\_deployment\_name) | n/a |
7474
| <a name="output_kms_key_arn"></a> [kms\_key\_arn](#output\_kms\_key\_arn) | n/a |
75+
| <a name="output_outputs_bucket_arn"></a> [outputs\_bucket\_arn](#output\_outputs\_bucket\_arn) | ARN of the S3 bucket storing module outputs |
76+
| <a name="output_outputs_bucket_name"></a> [outputs\_bucket\_name](#output\_outputs\_bucket\_name) | Name of the S3 bucket storing module outputs |
77+
| <a name="output_outputs_s3_uri"></a> [outputs\_s3\_uri](#output\_outputs\_s3\_uri) | S3 URI of the outputs.json file |
7578
| <a name="output_region"></a> [region](#output\_region) | n/a |
7679
<!-- END_TF_DOCS -->
7780

modules/controlplane_rift/infrastructure.tf

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,24 @@ module "tecton" {
2424
use_rift_cross_account_policy = true
2525
kms_key_id = var.kms_key_id
2626
}
27+
28+
# S3 module to store outputs
29+
module "s3_outputs" {
30+
source = "../s3_outputs"
31+
deployment_name = var.deployment_name
32+
33+
control_plane_account_id = var.tecton_control_plane_account_id
34+
35+
outputs_data = {
36+
deployment_name = var.deployment_name
37+
region = var.region
38+
cross_account_role_arn = module.tecton.cross_account_role_arn
39+
cross_account_external_id = var.cross_account_external_id
40+
kms_key_arn = module.tecton.kms_key_arn
41+
}
42+
43+
# Ensure S3 outputs are created after all other resources
44+
depends_on_resources = [
45+
module.tecton
46+
]
47+
}

modules/controlplane_rift/outputs.tf

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,20 @@ output "cross_account_external_id" {
1313

1414
output "kms_key_arn" {
1515
value = module.tecton.kms_key_arn
16+
}
17+
18+
# S3 outputs bucket information
19+
output "outputs_bucket_name" {
20+
description = "Name of the S3 bucket storing module outputs"
21+
value = module.s3_outputs.bucket_name
22+
}
23+
24+
output "outputs_bucket_arn" {
25+
description = "ARN of the S3 bucket storing module outputs"
26+
value = module.s3_outputs.bucket_arn
27+
}
28+
29+
output "outputs_s3_uri" {
30+
description = "S3 URI of the outputs.json file"
31+
value = module.s3_outputs.outputs_s3_uri
1632
}

modules/dataplane_rift/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ output "tecton" {
9999
| <a name="output_deployment_name"></a> [deployment\_name](#output\_deployment\_name) | Name of the Tecton deployment |
100100
| <a name="output_kms_key_arn"></a> [kms\_key\_arn](#output\_kms\_key\_arn) | ARN of the KMS key for encrypting data at rest |
101101
| <a name="output_nat_gateway_public_ips"></a> [nat\_gateway\_public\_ips](#output\_nat\_gateway\_public\_ips) | List of public IPs associated with NAT gateways in Rift VPC. Empty if existing\_vpc is provided as NATs are not managed by the module in that case. |
102+
| <a name="output_outputs_bucket_arn"></a> [outputs\_bucket\_arn](#output\_outputs\_bucket\_arn) | ARN of the S3 bucket storing module outputs |
103+
| <a name="output_outputs_bucket_name"></a> [outputs\_bucket\_name](#output\_outputs\_bucket\_name) | Name of the S3 bucket storing module outputs |
104+
| <a name="output_outputs_s3_uri"></a> [outputs\_s3\_uri](#output\_outputs\_s3\_uri) | S3 URI of the outputs.json file |
102105
| <a name="output_region"></a> [region](#output\_region) | Region of the Tecton deployment |
103106
| <a name="output_rift_compute_security_group_id"></a> [rift\_compute\_security\_group\_id](#output\_rift\_compute\_security\_group\_id) | Security Group ID for Rift compute instances |
104107
| <a name="output_vm_workload_subnet_ids"></a> [vm\_workload\_subnet\_ids](#output\_vm\_workload\_subnet\_ids) | List (comma-separated string) of subnet IDs for Rift compute instances |

modules/dataplane_rift/infrastructure.tf

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,33 @@ module "rift" {
5757
use_network_firewall = var.use_network_firewall
5858
# Domains can be extended as needed:
5959
additional_allowed_egress_domains = var.additional_allowed_egress_domains
60+
}
61+
62+
# S3 module to store outputs
63+
module "s3_outputs" {
64+
source = "../s3_outputs"
65+
deployment_name = var.deployment_name
66+
67+
control_plane_account_id = var.tecton_control_plane_account_id
68+
69+
outputs_data = {
70+
deployment_name = var.deployment_name
71+
region = var.region
72+
cross_account_role_arn = module.tecton.cross_account_role_arn
73+
cross_account_external_id = var.cross_account_external_id
74+
kms_key_arn = module.tecton.kms_key_arn
75+
compute_manager_arn = module.rift.compute_manager_arn
76+
compute_instance_profile_arn = module.rift.compute_instance_profile_arn
77+
compute_arn = module.rift.compute_arn
78+
vm_workload_subnet_ids = module.rift.vm_workload_subnet_ids
79+
anyscale_docker_target_repo = module.rift.anyscale_docker_target_repo
80+
nat_gateway_public_ips = module.rift.nat_gateway_public_ips
81+
rift_compute_security_group_id = module.rift.rift_compute_security_group_id
82+
}
83+
84+
# Ensure S3 outputs are created after all other resources
85+
depends_on_resources = [
86+
module.tecton,
87+
module.rift
88+
]
6089
}

modules/dataplane_rift/outputs.tf

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,19 @@ output "rift_compute_security_group_id" {
4646
description = "Security Group ID for Rift compute instances"
4747
value = module.rift.rift_compute_security_group_id
4848
}
49+
50+
# S3 outputs bucket information
51+
output "outputs_bucket_name" {
52+
description = "Name of the S3 bucket storing module outputs"
53+
value = module.s3_outputs.bucket_name
54+
}
55+
56+
output "outputs_bucket_arn" {
57+
description = "ARN of the S3 bucket storing module outputs"
58+
value = module.s3_outputs.bucket_arn
59+
}
60+
61+
output "outputs_s3_uri" {
62+
description = "S3 URI of the outputs.json file"
63+
value = module.s3_outputs.outputs_s3_uri
64+
}

modules/s3_outputs/README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# S3 Outputs Module
2+
3+
This shared sub-module creates an S3 bucket for each Tecton module and stores all module outputs as JSON files in that bucket.
4+
5+
## Features
6+
7+
- Creates a dedicated S3 bucket for each module
8+
- Stores outputs as `outputs.json` (latest) and timestamped files for versioning
9+
- Enables bucket versioning and encryption
10+
- Blocks public access for security
11+
12+
## Usage
13+
14+
Add this to your module's `infrastructure.tf` or `main.tf`:
15+
16+
```hcl
17+
module "s3_outputs" {
18+
source = "../s3_outputs"
19+
deployment_name = var.deployment_name
20+
module_name = "your-module-name" # e.g., "dataplane-rift", "controlplane", etc.
21+
22+
outputs_data = {
23+
# Include all outputs you want to store
24+
deployment_name = var.deployment_name
25+
region = var.region
26+
# ... add all other outputs from your outputs.tf
27+
}
28+
29+
# Ensure S3 outputs are created after all other resources
30+
depends_on_resources = [
31+
# List all modules that should be created first
32+
module.tecton,
33+
module.rift
34+
]
35+
}
36+
```
37+
38+
Then add these to your module's `outputs.tf`:
39+
40+
```hcl
41+
# S3 outputs bucket information
42+
output "outputs_bucket_name" {
43+
description = "Name of the S3 bucket storing module outputs"
44+
value = module.s3_outputs.bucket_name
45+
}
46+
47+
output "outputs_bucket_arn" {
48+
description = "ARN of the S3 bucket storing module outputs"
49+
value = module.s3_outputs.bucket_arn
50+
}
51+
52+
output "outputs_s3_uri" {
53+
description = "S3 URI of the outputs.json file"
54+
value = module.s3_outputs.outputs_s3_uri
55+
}
56+
```
57+
58+
<!-- BEGIN_TF_DOCS -->
59+
60+
## Providers
61+
62+
| Name | Version |
63+
|------|---------|
64+
| <a name="provider_aws"></a> [aws](#provider\_aws) | n/a |
65+
## Inputs
66+
67+
| Name | Description | Type | Default | Required |
68+
|------|-------------|------|---------|:--------:|
69+
| <a name="input_control_plane_account_id"></a> [control\_plane\_account\_id](#input\_control\_plane\_account\_id) | AWS account ID of the control plane | `string` | n/a | yes |
70+
| <a name="input_depends_on_resources"></a> [depends\_on\_resources](#input\_depends\_on\_resources) | List of resources that must be created before writing outputs | `list(any)` | `[]` | no |
71+
| <a name="input_deployment_name"></a> [deployment\_name](#input\_deployment\_name) | Name of the Tecton deployment | `string` | n/a | yes |
72+
| <a name="input_outputs_data"></a> [outputs\_data](#input\_outputs\_data) | Map of outputs data to store in S3 | `map(any)` | n/a | yes |
73+
| <a name="input_tags"></a> [tags](#input\_tags) | Additional tags to apply to resources | `map(string)` | `{}` | no |
74+
## Outputs
75+
76+
| Name | Description |
77+
|------|-------------|
78+
| <a name="output_bucket_arn"></a> [bucket\_arn](#output\_bucket\_arn) | ARN of the S3 bucket storing outputs |
79+
| <a name="output_bucket_name"></a> [bucket\_name](#output\_bucket\_name) | Name of the S3 bucket storing outputs |
80+
| <a name="output_outputs_s3_uri"></a> [outputs\_s3\_uri](#output\_outputs\_s3\_uri) | S3 URI of the outputs.json file |
81+
<!-- END_TF_DOCS -->

modules/s3_outputs/main.tf

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# S3 bucket for storing module outputs
2+
resource "aws_s3_bucket" "outputs" {
3+
bucket = "${var.deployment_name}-tecton-outputs"
4+
5+
tags = merge(var.tags, {
6+
Name = "${var.deployment_name}-tecton-outputs"
7+
Purpose = "TectonModuleOutputs"
8+
})
9+
}
10+
11+
# Bucket policy to allow control plane to read outputs
12+
resource "aws_s3_bucket_policy" "outputs" {
13+
bucket = aws_s3_bucket.outputs.id
14+
policy = jsonencode({
15+
Version = "2012-10-17"
16+
Statement = [
17+
{
18+
Effect = "Allow"
19+
Principal = {
20+
AWS = "arn:aws:iam::${var.control_plane_account_id}:root"
21+
}
22+
Action = [
23+
"s3:ListBucket"
24+
]
25+
Resource = "arn:aws:s3:::${aws_s3_bucket.outputs.id}"
26+
},
27+
{
28+
Effect = "Allow"
29+
Principal = {
30+
AWS = "arn:aws:iam::${var.control_plane_account_id}:root"
31+
}
32+
Action = [
33+
"s3:GetObject",
34+
"s3:GetObjectVersion"
35+
]
36+
Resource = "arn:aws:s3:::${aws_s3_bucket.outputs.id}/*"
37+
}
38+
]
39+
})
40+
depends_on = [aws_s3_bucket.outputs]
41+
}
42+
43+
resource "aws_s3_bucket_versioning" "outputs" {
44+
bucket = aws_s3_bucket.outputs.id
45+
versioning_configuration {
46+
status = "Enabled"
47+
}
48+
}
49+
50+
resource "aws_s3_bucket_server_side_encryption_configuration" "outputs" {
51+
bucket = aws_s3_bucket.outputs.id
52+
53+
rule {
54+
apply_server_side_encryption_by_default {
55+
sse_algorithm = "AES256"
56+
}
57+
}
58+
}
59+
60+
resource "aws_s3_bucket_public_access_block" "outputs" {
61+
bucket = aws_s3_bucket.outputs.id
62+
63+
block_public_acls = true
64+
block_public_policy = true
65+
ignore_public_acls = true
66+
restrict_public_buckets = true
67+
}
68+
69+
# Store the outputs as JSON in S3
70+
resource "aws_s3_object" "outputs_json" {
71+
bucket = aws_s3_bucket.outputs.id
72+
key = "outputs.json"
73+
content = jsonencode(var.outputs_data)
74+
content_type = "application/json"
75+
76+
# Ensure outputs are written after resources are created
77+
depends_on = [var.depends_on_resources]
78+
79+
tags = var.tags
80+
}
81+
82+
# Store outputs with timestamp for versioning
83+
resource "aws_s3_object" "outputs_timestamped" {
84+
bucket = aws_s3_bucket.outputs.id
85+
key = "outputs-${formatdate("YYYY-MM-DD-hhmm", timestamp())}.json"
86+
content = jsonencode(var.outputs_data)
87+
content_type = "application/json"
88+
89+
# Ensure outputs are written after resources are created
90+
depends_on = [var.depends_on_resources]
91+
92+
tags = var.tags
93+
}

modules/s3_outputs/outputs.tf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
output "bucket_name" {
2+
description = "Name of the S3 bucket storing outputs"
3+
value = aws_s3_bucket.outputs.bucket
4+
}
5+
6+
output "bucket_arn" {
7+
description = "ARN of the S3 bucket storing outputs"
8+
value = aws_s3_bucket.outputs.arn
9+
}
10+
11+
output "outputs_s3_uri" {
12+
description = "S3 URI of the outputs.json file"
13+
value = "s3://${aws_s3_bucket.outputs.bucket}/outputs.json"
14+
}

modules/s3_outputs/variables.tf

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
variable "deployment_name" {
2+
description = "Name of the Tecton deployment"
3+
type = string
4+
}
5+
6+
variable "outputs_data" {
7+
description = "Map of outputs data to store in S3"
8+
type = map(any)
9+
}
10+
11+
variable "tags" {
12+
description = "Additional tags to apply to resources"
13+
type = map(string)
14+
default = {}
15+
}
16+
17+
variable "depends_on_resources" {
18+
description = "List of resources that must be created before writing outputs"
19+
type = list(any)
20+
default = []
21+
}
22+
23+
variable "control_plane_account_id" {
24+
description = "AWS account ID of the control plane"
25+
type = string
26+
}

0 commit comments

Comments
 (0)