Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 40 additions & 49 deletions aws/examples/simple/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 45 additions & 1 deletion aws/examples/simple/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ This example provisions the following infrastructure:
### Materialize
- **Operator**: Materialize Kubernetes operator
- **Instance**: Single Materialize instance in `materialize-environment` namespace
- **Network Load Balancer**: Dedicated internal NLB for Materialize access (ports 6875, 6876, 8080)
- **Network Load Balancer**: Internet-facing NLB for Materialize access (ports 6875, 6876, 8080)

---

Expand Down Expand Up @@ -82,6 +82,50 @@ terraform apply

---

### Step 3: Accessing Materialize

#### Security Model
This deployment implements a secure access model:
- **Public Access**: Only allowed via the Network Load Balancer (NLB).
- **Direct Node Access**: **BLOCKED**. The EKS nodes have a security group that only accepts traffic from within the VPC.

#### Access Methods

**If using a public (internet-facing) NLB:**

Both SQL and Console are available via the public NLB:

- **SQL Access**: Connect using any PostgreSQL-compatible client pointing to the NLB's DNS name on port **6875**
- **Console Access**: Access the Materialize Console via the NLB's DNS name on port **8080**

To get the NLB DNS name:
```bash
terraform output -json | jq -r .nlb_dns_name.value
```

**If using a private (internal) NLB:**

Use Kubernetes port-forwarding for both SQL and Console. `kubectl port-forward` creates a TCP tunnel that preserves the underlying protocol (pgwire for SQL, HTTP for Console):

- **SQL Access**:
```bash
# Forward local port 6875 to the Materialize balancerd service
kubectl port-forward svc/mz<resource-id>-balancerd 6875:6875 -n materialize-environment
```
Then connect your PostgreSQL client to `localhost:6875`. The pgwire protocol is preserved through the TCP tunnel.

- **Console Access**:
```bash
# Forward local port 8080 to the Materialize console service
kubectl port-forward svc/mz<resource-id>-console 8080:8080 -n materialize-environment
```
Then open your browser to `http://localhost:8080`. HTTP traffic is preserved through the TCP tunnel.

**Note on NLB Layer 4 operation:**
The NLB operates at Layer 4 (TCP), forwarding connections without interpreting application-layer protocols. This works correctly for both pgwire (port 6875) and HTTP console access (port 8080), as both protocols run over TCP. The NLB forwards the TCP packets to the backend services, which handle the respective protocols.

---

## Notes

* You can customize each module independently.
Expand Down
4 changes: 4 additions & 0 deletions aws/examples/simple/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ module "eks" {
private_subnet_ids = module.networking.private_subnet_ids
cluster_enabled_log_types = ["api", "audit"]
enable_cluster_creator_admin_permissions = true
materialize_node_ingress_cidrs = [module.networking.vpc_cidr_block]
tags = var.tags

depends_on = [
Expand Down Expand Up @@ -367,9 +368,12 @@ module "materialize_nlb" {
name_prefix = var.name_prefix
namespace = local.materialize_instance_namespace
subnet_ids = module.networking.private_subnet_ids
internal = true
enable_cross_zone_load_balancing = true
vpc_id = module.networking.vpc_id
mz_resource_id = module.materialize_instance.instance_resource_id
node_security_group_id = module.eks.node_security_group_id
ingress_cidr_blocks = var.ingress_cidr_blocks

tags = var.tags

Expand Down
7 changes: 7 additions & 0 deletions aws/examples/simple/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,10 @@ variable "request_rollout" {
type = string
default = "00000000-0000-0000-0000-000000000001"
}

variable "ingress_cidr_blocks" {
description = "List of CIDR blocks to allow access to materialize."
type = list(string)
default = ["0.0.0.0/0"]
nullable = false
}
1 change: 1 addition & 0 deletions aws/modules/eks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ No resources.
| <a name="input_cluster_version"></a> [cluster\_version](#input\_cluster\_version) | Kubernetes version for the EKS cluster | `string` | `"1.32"` | no |
| <a name="input_enable_cluster_creator_admin_permissions"></a> [enable\_cluster\_creator\_admin\_permissions](#input\_enable\_cluster\_creator\_admin\_permissions) | To add the current caller identity as an administrator | `bool` | `true` | no |
| <a name="input_iam_role_use_name_prefix"></a> [iam\_role\_use\_name\_prefix](#input\_iam\_role\_use\_name\_prefix) | Use name prefix for IAM roles | `bool` | `true` | no |
| <a name="input_materialize_node_ingress_cidrs"></a> [materialize\_node\_ingress\_cidrs](#input\_materialize\_node\_ingress\_cidrs) | List of CIDR blocks to allow ingress from for Materialize ports (HTTP 6876, pgwire 6875, health checks 8080). | `list(string)` | n/a | yes |
| <a name="input_name_prefix"></a> [name\_prefix](#input\_name\_prefix) | Prefix for all resource names | `string` | n/a | yes |
| <a name="input_private_subnet_ids"></a> [private\_subnet\_ids](#input\_private\_subnet\_ids) | List of private subnet IDs for EKS | `list(string)` | n/a | yes |
| <a name="input_tags"></a> [tags](#input\_tags) | Tags to apply to all resources | `map(string)` | `{}` | no |
Expand Down
39 changes: 18 additions & 21 deletions aws/modules/eks/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,28 @@ module "eks" {

node_security_group_additional_rules = {
mz_ingress_http = {
description = "Ingress to materialize balancers HTTP"
protocol = "tcp"
from_port = 6876
to_port = 6876
type = "ingress"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
description = "Ingress to materialize balancers HTTP"
protocol = "tcp"
from_port = 6876
to_port = 6876
type = "ingress"
cidr_blocks = var.materialize_node_ingress_cidrs
}
mz_ingress_pgwire = {
description = "Ingress to materialize balancers pgwire"
protocol = "tcp"
from_port = 6875
to_port = 6875
type = "ingress"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
description = "Ingress to materialize balancers pgwire"
protocol = "tcp"
from_port = 6875
to_port = 6875
type = "ingress"
cidr_blocks = var.materialize_node_ingress_cidrs
}
mz_ingress_nlb_health_checks = {
description = "Ingress to materialize balancer health checks and console"
protocol = "tcp"
from_port = 8080
to_port = 8080
type = "ingress"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
description = "Ingress to materialize balancer health checks and console"
protocol = "tcp"
from_port = 8080
to_port = 8080
type = "ingress"
cidr_blocks = var.materialize_node_ingress_cidrs
}
}

Expand Down
10 changes: 10 additions & 0 deletions aws/modules/eks/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,13 @@ variable "iam_role_use_name_prefix" {
nullable = false
}

variable "materialize_node_ingress_cidrs" {
description = "List of CIDR blocks to allow ingress from for Materialize ports (HTTP 6876, pgwire 6875, health checks 8080)."
type = list(string)
nullable = false

validation {
condition = alltrue([for cidr in var.materialize_node_ingress_cidrs : can(cidrhost(cidr, 0))])
error_message = "All CIDR blocks must be valid IPv4 CIDR notation (e.g., '10.0.0.0/16' or '0.0.0.0/0')."
}
}
12 changes: 11 additions & 1 deletion aws/modules/nlb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,26 @@
| Name | Type |
|------|------|
| [aws_lb.nlb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb) | resource |
| [aws_security_group.nlb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_security_group_rule.allow_nlb_to_nodes_health](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.allow_nlb_to_nodes_http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.allow_nlb_to_nodes_pgwire](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_vpc_security_group_ingress_rule.nlb_console](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource |
| [aws_vpc_security_group_ingress_rule.nlb_http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource |
| [aws_vpc_security_group_ingress_rule.nlb_pgwire](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_enable_cross_zone_load_balancing"></a> [enable\_cross\_zone\_load\_balancing](#input\_enable\_cross\_zone\_load\_balancing) | Whether to enable cross zone load balancing on the NLB. | `bool` | `true` | no |
| <a name="input_ingress_cidr_blocks"></a> [ingress\_cidr\_blocks](#input\_ingress\_cidr\_blocks) | List of CIDR blocks to allow ingress to the NLB Security Group. | `list(string)` | n/a | yes |
| <a name="input_instance_name"></a> [instance\_name](#input\_instance\_name) | The name of the Materialize instance. | `string` | n/a | yes |
| <a name="input_internal"></a> [internal](#input\_internal) | Whether the NLB is internal only. Defaults to true to avoid exposing Materialize to the internet. | `bool` | `true` | no |
| <a name="input_internal"></a> [internal](#input\_internal) | Whether the NLB is internal only. Defaults to false (public) to allow external access to Materialize. Set to true for VPC-only access. | `bool` | `true` | no |
| <a name="input_mz_resource_id"></a> [mz\_resource\_id](#input\_mz\_resource\_id) | The resourceId from the Materialize CR | `string` | n/a | yes |
| <a name="input_name_prefix"></a> [name\_prefix](#input\_name\_prefix) | Prefix to use for NLB, Target Groups, Listeners, and TargetGroupBindings | `string` | n/a | yes |
| <a name="input_namespace"></a> [namespace](#input\_namespace) | Kubernetes namespace in which to install TargetGroupBindings | `string` | n/a | yes |
| <a name="input_node_security_group_id"></a> [node\_security\_group\_id](#input\_node\_security\_group\_id) | ID of the EKS Node Security Group to allow traffic to. Used to add ingress rules from the NLB SG. | `string` | n/a | yes |
| <a name="input_subnet_ids"></a> [subnet\_ids](#input\_subnet\_ids) | A list of subnet IDs in which to install the NLB. Must be in the VPC. | `list(string)` | n/a | yes |
| <a name="input_tags"></a> [tags](#input\_tags) | Tags to apply to all resources | `map(string)` | `{}` | no |
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | ID of the VPC | `string` | n/a | yes |
Expand All @@ -49,3 +58,4 @@
| <a name="output_instance_name"></a> [instance\_name](#output\_instance\_name) | The name of the Materialize instance. |
| <a name="output_nlb_arn"></a> [nlb\_arn](#output\_nlb\_arn) | ARN of the Network Load Balancer. |
| <a name="output_nlb_dns_name"></a> [nlb\_dns\_name](#output\_nlb\_dns\_name) | DNS name of the Network Load Balancer. |
| <a name="output_security_group_id"></a> [security\_group\_id](#output\_security\_group\_id) | The ID of the security group attached to the NLB |
Loading