diff --git a/docs/resources/namespace.md b/docs/resources/namespace.md
index 4ed4759..a6fc81a 100644
--- a/docs/resources/namespace.md
+++ b/docs/resources/namespace.md
@@ -24,6 +24,7 @@ description: |-
### Optional
+- `certificate_filters` (Attributes List) (see [below for nested schema](#nestedatt--certificate_filters))
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
@@ -31,6 +32,17 @@ description: |-
- `id` (String) The ID of this resource.
- `resource_version` (String)
+
+### Nested Schema for `certificate_filters`
+
+Optional:
+
+- `common_name` (String)
+- `organization` (String)
+- `organizational_unit` (String)
+- `subject_alternative_name` (String)
+
+
### Nested Schema for `timeouts`
diff --git a/internal/provider/namespace_resource.go b/internal/provider/namespace_resource.go
index f2e960e..e94156f 100644
--- a/internal/provider/namespace_resource.go
+++ b/internal/provider/namespace_resource.go
@@ -28,12 +28,14 @@ import (
"time"
"github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/temporalio/terraform-provider-temporalcloud/internal/client"
cloudservicev1 "github.com/temporalio/terraform-provider-temporalcloud/proto/go/temporal/api/cloud/cloudservice/v1"
@@ -51,19 +53,35 @@ type (
}
namespaceResourceModel struct {
- ID types.String `tfsdk:"id"`
- Name types.String `tfsdk:"name"`
- Regions types.List `tfsdk:"regions"`
- AcceptedClientCA types.String `tfsdk:"accepted_client_ca"`
- RetentionDays types.Int64 `tfsdk:"retention_days"`
- ResourceVersion types.String `tfsdk:"resource_version"`
- Timeouts timeouts.Value `tfsdk:"timeouts"`
+ ID types.String `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ Regions types.List `tfsdk:"regions"`
+ AcceptedClientCA types.String `tfsdk:"accepted_client_ca"`
+ RetentionDays types.Int64 `tfsdk:"retention_days"`
+ ResourceVersion types.String `tfsdk:"resource_version"`
+ CertificateFilters types.List `tfsdk:"certificate_filters"`
+
+ Timeouts timeouts.Value `tfsdk:"timeouts"`
+ }
+
+ namespaceCertificateFilterModel struct {
+ CommonName types.String `tfsdk:"common_name"`
+ Organization types.String `tfsdk:"organization"`
+ OrganizationalUnit types.String `tfsdk:"organizational_unit"`
+ SubjectAlternativeName types.String `tfsdk:"subject_alternative_name"`
}
)
var (
_ resource.Resource = (*namespaceResource)(nil)
_ resource.ResourceWithConfigure = (*namespaceResource)(nil)
+
+ namespaceCertificateFilterAttrs = map[string]attr.Type{
+ "common_name": types.StringType,
+ "organization": types.StringType,
+ "organizational_unit": types.StringType,
+ "subject_alternative_name": types.StringType,
+ }
)
func NewNamespaceResource() resource.Resource {
@@ -119,6 +137,25 @@ func (r *namespaceResource) Schema(ctx context.Context, _ resource.SchemaRequest
"resource_version": schema.StringAttribute{
Computed: true,
},
+ "certificate_filters": schema.ListNestedAttribute{
+ Optional: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "common_name": schema.StringAttribute{
+ Optional: true,
+ },
+ "organization": schema.StringAttribute{
+ Optional: true,
+ },
+ "organizational_unit": schema.StringAttribute{
+ Optional: true,
+ },
+ "subject_alternative_name": schema.StringAttribute{
+ Optional: true,
+ },
+ },
+ },
+ },
},
Blocks: map[string]schema.Block{
"timeouts": timeouts.Block(ctx, timeouts.Opts{
@@ -150,13 +187,18 @@ func (r *namespaceResource) Create(ctx context.Context, req resource.CreateReque
if resp.Diagnostics.HasError() {
return
}
+ certFilters := getCertFiltersFromModel(ctx, resp.Diagnostics, &plan)
+ if resp.Diagnostics.HasError() {
+ return
+ }
svcResp, err := r.client.CreateNamespace(ctx, &cloudservicev1.CreateNamespaceRequest{
Spec: &namespacev1.NamespaceSpec{
Name: plan.Name.ValueString(),
Regions: regions,
RetentionDays: int32(plan.RetentionDays.ValueInt64()),
MtlsAuth: &namespacev1.MtlsAuthSpec{
- AcceptedClientCa: plan.AcceptedClientCA.ValueString(),
+ AcceptedClientCa: plan.AcceptedClientCA.ValueString(),
+ CertificateFilters: certFilters,
},
},
})
@@ -217,6 +259,10 @@ func (r *namespaceResource) Update(ctx context.Context, req resource.UpdateReque
if resp.Diagnostics.HasError() {
return
}
+ certFilters := getCertFiltersFromModel(ctx, resp.Diagnostics, &plan)
+ if resp.Diagnostics.HasError() {
+ return
+ }
svcResp, err := r.client.UpdateNamespace(ctx, &cloudservicev1.UpdateNamespaceRequest{
Namespace: plan.ID.ValueString(),
Spec: &namespacev1.NamespaceSpec{
@@ -224,7 +270,8 @@ func (r *namespaceResource) Update(ctx context.Context, req resource.UpdateReque
Regions: regions,
RetentionDays: int32(plan.RetentionDays.ValueInt64()),
MtlsAuth: &namespacev1.MtlsAuthSpec{
- AcceptedClientCa: plan.AcceptedClientCA.ValueString(),
+ AcceptedClientCa: plan.AcceptedClientCA.ValueString(),
+ CertificateFilters: certFilters,
},
},
ResourceVersion: plan.ResourceVersion.ValueString(),
@@ -304,8 +351,63 @@ func updateModelFromSpec(ctx context.Context, diags diag.Diagnostics, state *nam
return
}
+ certificateFilterObjects := make([]types.Object, len(ns.GetSpec().GetMtlsAuth().GetCertificateFilters()))
+ for i, certFilter := range ns.GetSpec().GetMtlsAuth().GetCertificateFilters() {
+ model := namespaceCertificateFilterModel{
+ CommonName: stringOrNull(certFilter.GetCommonName()),
+ Organization: stringOrNull(certFilter.GetOrganization()),
+ OrganizationalUnit: stringOrNull(certFilter.GetOrganizationalUnit()),
+ SubjectAlternativeName: stringOrNull(certFilter.GetSubjectAlternativeName()),
+ }
+ obj, diag := types.ObjectValueFrom(ctx, namespaceCertificateFilterAttrs, model)
+ diags.Append(diag...)
+ if diags.HasError() {
+ return
+ }
+ certificateFilterObjects[i] = obj
+ }
+
+ certificateFilter, diag := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: namespaceCertificateFilterAttrs}, certificateFilterObjects)
+ diags.Append(diag...)
+ if diags.HasError() {
+ return
+ }
state.Regions = planRegions
+ state.CertificateFilters = certificateFilter
state.AcceptedClientCA = types.StringValue(ns.GetSpec().GetMtlsAuth().GetAcceptedClientCa())
state.RetentionDays = types.Int64Value(int64(ns.GetSpec().GetRetentionDays()))
state.ResourceVersion = types.StringValue(ns.GetResourceVersion())
}
+
+func getCertFiltersFromModel(ctx context.Context, diags diag.Diagnostics, model *namespaceResourceModel) []*namespacev1.CertificateFilterSpec {
+ elements := make([]types.Object, 0, len(model.CertificateFilters.Elements()))
+ diags.Append(model.CertificateFilters.ElementsAs(ctx, &elements, false)...)
+ if diags.HasError() {
+ return nil
+ }
+
+ certificateFilters := make([]*namespacev1.CertificateFilterSpec, len(elements))
+ for i, filter := range elements {
+ var model namespaceCertificateFilterModel
+ diags.Append(filter.As(ctx, &model, basetypes.ObjectAsOptions{})...)
+ if diags.HasError() {
+ return nil
+ }
+
+ certificateFilters[i] = &namespacev1.CertificateFilterSpec{
+ CommonName: model.CommonName.ValueString(),
+ Organization: model.Organization.ValueString(),
+ OrganizationalUnit: model.OrganizationalUnit.ValueString(),
+ SubjectAlternativeName: model.SubjectAlternativeName.ValueString(),
+ }
+ }
+
+ return certificateFilters
+}
+
+func stringOrNull(s string) types.String {
+ if s == "" {
+ return types.StringNull()
+ }
+ return types.StringValue(s)
+}
diff --git a/internal/provider/namespace_resource_test.go b/internal/provider/namespace_resource_test.go
index df79fc3..85f9e39 100644
--- a/internal/provider/namespace_resource_test.go
+++ b/internal/provider/namespace_resource_test.go
@@ -51,6 +51,12 @@ cmFsLlB1VHMwCgYIKoZIzj0EAwMDZwAwZAIwRLfm9S7rKGd30KdQvUMcOcDJlmDw
-----END CERTIFICATE-----
PEM
)
+
+ certificate_filters = [
+ {
+ subject_alternative_name = "example.com"
+ }
+ ]
retention_days = %d
}