Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,36 @@ The module supports several rollout strategies for Materialize instances through

To use these options, set the appropriate values in the `instances` input variable and when you want to rollout a new version of the instance, set the `request_rollout` or `force_rollout` value to a new UUID.

## Authentication Options

The module supports two authentication modes for Materialize instances:

### `authenticator_kind` (string)
- Determines how users authenticate with the Materialize instance.
- Valid values are:
- `"None"` (default): No password authentication is enabled.
- `"Password"`: Enables password authentication for the `mz_system` user. When set to `"Password"`, you **must** provide a value for `external_login_password_mz_system`.

### `external_login_password_mz_system` (string)
- The password to set for the `mz_system` user when `authenticator_kind` is `"Password"`.
- This value is stored securely in a Kubernetes Secret and used by the Materialize operator to configure authentication.
- **Required** if `authenticator_kind` is set to `"Password"`.

**Example:**
```hcl
instances = [
{
name = "mz-instance"
namespace = "mz-ns"
authenticator_kind = "Password"
external_login_password_mz_system = "your-secure-password"
# other instance configurations
}
]
```

If `authenticator_kind` is not set or set to `"None"`, password authentication is disabled and `external_login_password_mz_system` is ignored.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we cause an error instead? I'm afraid someone might set external_login_password_mz_system and be confused that they can still log in without a password because they forgot to set the authenticator_kind.

An even more intuitive scheme would be to only have a password, and if it's set, switch the authenticator kind to password, otherwise none.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! Just updated this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree this is the easiest to use, but it's also creates an interface that doesn't map with the k8s crd or envd binary. In this case, I think the cleanest thing to do is mirror the underlying behavior.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm yes, I see your point. I do like the simplicity of the implicit behavior, but happy to revert the last change if @def- and @alex-hunt-materialize agree that staying closer to the original model is the better call here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also make it more intuitive in k8s crd/envd binary!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my experience it's generally acceptable to only read flags for a feature when that feature is enabled and to ignore them when the feature is disabled without error. This is especially true on the helm chart side.

I think keeping our logic to match the CRD (not doing any TF magic) is going to provide the best continuity of understanding as users dig deeper into problems and start looking at k8s directly. It's definitely possible that we want to simplify the crd/envd binary. I think we can resist that later, especially if the configuration gets more complex.


## Requirements

| Name | Version |
Expand Down Expand Up @@ -77,7 +107,7 @@ No modules.
| <a name="input_helm_repository"></a> [helm\_repository](#input\_helm\_repository) | Repository URL for the Materialize operator Helm chart. Leave empty if using local chart. | `string` | `"https://materializeinc.github.io/materialize/"` | no |
| <a name="input_helm_values"></a> [helm\_values](#input\_helm\_values) | Values to pass to the Helm chart | `any` | n/a | yes |
| <a name="input_install_metrics_server"></a> [install\_metrics\_server](#input\_install\_metrics\_server) | Whether to install the metrics-server | `bool` | `true` | no |
| <a name="input_instances"></a> [instances](#input\_instances) | Configuration for Materialize instances | <pre>list(object({<br/> name = string<br/> namespace = optional(string)<br/> create_database = optional(bool, true)<br/> database_name = string<br/> metadata_backend_url = string<br/> persist_backend_url = string<br/> license_key = optional(string)<br/> environmentd_version = optional(string, "v0.130.13") # META: mz version<br/> environmentd_extra_env = optional(list(object({<br/> name = string<br/> value = string<br/> })), [])<br/> environmentd_extra_args = optional(list(string), [])<br/> cpu_request = optional(string, "1")<br/> memory_request = optional(string, "1Gi")<br/> memory_limit = optional(string, "1Gi")<br/> in_place_rollout = optional(bool, true)<br/> request_rollout = optional(string, "00000000-0000-0000-0000-000000000001")<br/> force_rollout = optional(string, "00000000-0000-0000-0000-000000000001")<br/> balancer_memory_request = optional(string, "256Mi")<br/> balancer_memory_limit = optional(string, "256Mi")<br/> balancer_cpu_request = optional(string, "100m")<br/> }))</pre> | `[]` | no |
| <a name="input_instances"></a> [instances](#input\_instances) | Configuration for Materialize instances | <pre>list(object({<br/> name = string<br/> namespace = optional(string)<br/> create_database = optional(bool, true)<br/> database_name = string<br/> metadata_backend_url = string<br/> persist_backend_url = string<br/> license_key = optional(string)<br/> external_login_password_mz_system = optional(string)<br/> authenticator_kind = optional(string, "None")<br/> environmentd_version = optional(string, "v0.130.13") # META: mz version<br/> environmentd_extra_env = optional(list(object({<br/> name = string<br/> value = string<br/> })), [])<br/> environmentd_extra_args = optional(list(string), [])<br/> cpu_request = optional(string, "1")<br/> memory_request = optional(string, "1Gi")<br/> memory_limit = optional(string, "1Gi")<br/> in_place_rollout = optional(bool, true)<br/> request_rollout = optional(string, "00000000-0000-0000-0000-000000000001")<br/> force_rollout = optional(string, "00000000-0000-0000-0000-000000000001")<br/> balancer_memory_request = optional(string, "256Mi")<br/> balancer_memory_limit = optional(string, "256Mi")<br/> balancer_cpu_request = optional(string, "100m")<br/> }))</pre> | `[]` | no |
| <a name="input_metrics_server_version"></a> [metrics\_server\_version](#input\_metrics\_server\_version) | Version of metrics-server to install | `string` | `"3.12.2"` | no |
| <a name="input_monitoring_namespace"></a> [monitoring\_namespace](#input\_monitoring\_namespace) | Namespace for monitoring resources | `string` | `"monitoring"` | no |
| <a name="input_namespace"></a> [namespace](#input\_namespace) | Namespace prefix for all resources | `string` | n/a | yes |
Expand Down
30 changes: 30 additions & 0 deletions docs/header.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,33 @@ The module supports several rollout strategies for Materialize instances through
- Must be changed to a new UUID value for each rollout

To use these options, set the appropriate values in the `instances` input variable and when you want to rollout a new version of the instance, set the `request_rollout` or `force_rollout` value to a new UUID.

## Authentication Options

The module supports two authentication modes for Materialize instances:

### `authenticator_kind` (string)
- Determines how users authenticate with the Materialize instance.
- Valid values are:
- `"None"` (default): No password authentication is enabled.
- `"Password"`: Enables password authentication for the `mz_system` user. When set to `"Password"`, you **must** provide a value for `external_login_password_mz_system`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is totally fine, but we could also generate one for them if they don't provide one.


### `external_login_password_mz_system` (string)
- The password to set for the `mz_system` user when `authenticator_kind` is `"Password"`.
- This value is stored securely in a Kubernetes Secret and used by the Materialize operator to configure authentication.
- **Required** if `authenticator_kind` is set to `"Password"`.

**Example:**
```hcl
instances = [
{
name = "mz-instance"
namespace = "mz-ns"
authenticator_kind = "Password"
external_login_password_mz_system = "your-secure-password"
# other instance configurations
}
]
```

If `authenticator_kind` is not set or set to `"None"`, password authentication is disabled and `external_login_password_mz_system` is ignored.
16 changes: 11 additions & 5 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,16 @@ resource "kubernetes_secret" "materialize_backends" {
namespace = coalesce(each.value.namespace, var.operator_namespace)
}

data = {
metadata_backend_url = each.value.metadata_backend_url
persist_backend_url = each.value.persist_backend_url
license_key = each.value.license_key == null ? "" : each.value.license_key
}
data = merge(
{
metadata_backend_url = each.value.metadata_backend_url
persist_backend_url = each.value.persist_backend_url
license_key = each.value.license_key == null ? "" : each.value.license_key
},
each.value.authenticator_kind == "Password" && each.value.external_login_password_mz_system != null ? {
external_login_password_mz_system = each.value.external_login_password_mz_system
} : {}
)

depends_on = [
kubernetes_namespace.instance_namespaces,
Expand Down Expand Up @@ -102,6 +107,7 @@ resource "kubernetes_manifest" "materialize_instances" {
spec = {
environmentdImageRef = "materialize/environmentd:${each.value.environmentd_version}"
backendSecretName = "${each.key}-materialize-backend"
authenticatorKind = each.value.authenticator_kind
inPlaceRollout = each.value.in_place_rollout
requestRollout = lookup(each.value, "request_rollout", null)
forceRollout = lookup(each.value, "force_rollout", null)
Expand Down
34 changes: 26 additions & 8 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,16 @@ variable "install_metrics_server" {
variable "instances" {
description = "Configuration for Materialize instances"
type = list(object({
name = string
namespace = optional(string)
create_database = optional(bool, true)
database_name = string
metadata_backend_url = string
persist_backend_url = string
license_key = optional(string)
environmentd_version = optional(string, "v0.130.13") # META: mz version
name = string
namespace = optional(string)
create_database = optional(bool, true)
database_name = string
metadata_backend_url = string
persist_backend_url = string
license_key = optional(string)
external_login_password_mz_system = optional(string)
authenticator_kind = optional(string, "None")
environmentd_version = optional(string, "v0.130.13") # META: mz version
environmentd_extra_env = optional(list(object({
name = string
value = string
Expand Down Expand Up @@ -107,6 +109,22 @@ variable "instances" {
])
error_message = "Force rollout must be a valid UUID in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

validation {
condition = alltrue([
for instance in var.instances :
contains(["Password", "None"], instance.authenticator_kind)
])
error_message = "Authenticator kind must be either 'Password' or 'None'"
}

validation {
condition = alltrue([
for instance in var.instances :
instance.authenticator_kind != "Password" || instance.external_login_password_mz_system != null
])
error_message = "When authenticator_kind is 'Password', external_login_password_mz_system must be provided"
}
}

variable "postgres_version" {
Expand Down