Skip to content

Commit

Permalink
Merge pull request #53 from ClickHouse/add-customer-encryption-
Browse files Browse the repository at this point in the history
add managed encryption to service creation
  • Loading branch information
serdec authored Apr 9, 2024
2 parents 4902c72 + 8f657d8 commit 0937bc5
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 49 deletions.
36 changes: 21 additions & 15 deletions clickhouse/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,23 +65,29 @@ type ServicePrivateEndpointConfig struct {
EndpointServiceId string `json:"endpointServiceId,omitempty"`
PrivateDnsHostname string `json:"privateDnsHostname,omitempty"`
}
type ServiceManagedEncryption struct {
KeyArn string `json:"keyArn,omitempty"`
AssumeRoleArn string `json:"assumeRoleArn,omitempty"`
}

type Service struct {
Id string `json:"id,omitempty"`
Name string `json:"name"`
Provider string `json:"provider"`
Region string `json:"region"`
Tier string `json:"tier"`
IdleScaling bool `json:"idleScaling"`
IpAccessList []IpAccess `json:"ipAccessList"`
MinTotalMemoryGb *int `json:"minTotalMemoryGb,omitempty"`
MaxTotalMemoryGb *int `json:"maxTotalMemoryGb,omitempty"`
IdleTimeoutMinutes *int `json:"idleTimeoutMinutes,omitempty"`
State string `json:"state,omitempty"`
Endpoints []Endpoint `json:"endpoints,omitempty"`
IAMRole string `json:"iamRole,omitempty"`
PrivateEndpointConfig *ServicePrivateEndpointConfig `json:"privateEndpointConfig,omitempty"`
PrivateEndpointIds []string `json:"privateEndpointIds,omitempty"`
Id string `json:"id,omitempty"`
Name string `json:"name"`
Provider string `json:"provider"`
Region string `json:"region"`
Tier string `json:"tier"`
IdleScaling bool `json:"idleScaling"`
IpAccessList []IpAccess `json:"ipAccessList"`
MinTotalMemoryGb *int `json:"minTotalMemoryGb,omitempty"`
MaxTotalMemoryGb *int `json:"maxTotalMemoryGb,omitempty"`
IdleTimeoutMinutes *int `json:"idleTimeoutMinutes,omitempty"`
State string `json:"state,omitempty"`
Endpoints []Endpoint `json:"endpoints,omitempty"`
IAMRole string `json:"iamRole,omitempty"`
PrivateEndpointConfig *ServicePrivateEndpointConfig `json:"privateEndpointConfig,omitempty"`
PrivateEndpointIds []string `json:"privateEndpointIds,omitempty"`
EncryptionKey string `json:"encryptionKey,omitempty"`
EncryptionAssumedRoleIdentifier string `json:"encryptionAssumedRoleIdentifier,omitempty"`
}

type ServiceUpdate struct {
Expand Down
127 changes: 93 additions & 34 deletions clickhouse/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package clickhouse

import (
"context"
"strings"
"time"

"github.com/hashicorp/terraform-plugin-framework/attr"
Expand Down Expand Up @@ -34,24 +35,26 @@ type ServiceResource struct {
}

type ServiceResourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Password types.String `tfsdk:"password"`
PasswordHash types.String `tfsdk:"password_hash"`
DoubleSha1PasswordHash types.String `tfsdk:"double_sha1_password_hash"`
Endpoints types.List `tfsdk:"endpoints"`
CloudProvider types.String `tfsdk:"cloud_provider"`
Region types.String `tfsdk:"region"`
Tier types.String `tfsdk:"tier"`
IdleScaling types.Bool `tfsdk:"idle_scaling"`
IpAccessList []IpAccessModel `tfsdk:"ip_access"`
MinTotalMemoryGb types.Int64 `tfsdk:"min_total_memory_gb"`
MaxTotalMemoryGb types.Int64 `tfsdk:"max_total_memory_gb"`
IdleTimeoutMinutes types.Int64 `tfsdk:"idle_timeout_minutes"`
IAMRole types.String `tfsdk:"iam_role"`
LastUpdated types.String `tfsdk:"last_updated"`
PrivateEndpointConfig types.Object `tfsdk:"private_endpoint_config"`
PrivateEndpointIds types.List `tfsdk:"private_endpoint_ids"`
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Password types.String `tfsdk:"password"`
PasswordHash types.String `tfsdk:"password_hash"`
DoubleSha1PasswordHash types.String `tfsdk:"double_sha1_password_hash"`
Endpoints types.List `tfsdk:"endpoints"`
CloudProvider types.String `tfsdk:"cloud_provider"`
Region types.String `tfsdk:"region"`
Tier types.String `tfsdk:"tier"`
IdleScaling types.Bool `tfsdk:"idle_scaling"`
IpAccessList []IpAccessModel `tfsdk:"ip_access"`
MinTotalMemoryGb types.Int64 `tfsdk:"min_total_memory_gb"`
MaxTotalMemoryGb types.Int64 `tfsdk:"max_total_memory_gb"`
IdleTimeoutMinutes types.Int64 `tfsdk:"idle_timeout_minutes"`
IAMRole types.String `tfsdk:"iam_role"`
LastUpdated types.String `tfsdk:"last_updated"`
PrivateEndpointConfig types.Object `tfsdk:"private_endpoint_config"`
PrivateEndpointIds types.List `tfsdk:"private_endpoint_ids"`
EncryptionKey types.String `tfsdk:"encryption_key"`
EncryptionAssumedRoleIdentifier types.String `tfsdk:"encryption_assumed_role_identifier"`
}

var endpointObjectType = types.ObjectType{
Expand Down Expand Up @@ -205,6 +208,14 @@ func (r *ServiceResource) Schema(_ context.Context, _ resource.SchemaRequest, re
Computed: true,
Default: listdefault.StaticValue(createEmptyList(types.StringType)),
},
"encryption_key": schema.StringAttribute{
Description: "Custom encryption key arn",
Optional: true,
},
"encryption_assumed_role_identifier": schema.StringAttribute{
Description: "Custom role identifier arn ",
Optional: true,
},
},
}
}
Expand Down Expand Up @@ -244,31 +255,60 @@ func (r *ServiceResource) Create(ctx context.Context, req resource.CreateRequest
)
return
}
} else if service.Tier == "production" {
if plan.IdleScaling.ValueBool() && (plan.IdleScaling.IsNull() || plan.MinTotalMemoryGb.IsNull() || plan.MaxTotalMemoryGb.IsNull() || plan.IdleTimeoutMinutes.IsNull()) {

if !plan.EncryptionKey.IsNull() || !plan.EncryptionAssumedRoleIdentifier.IsNull(){
resp.Diagnostics.AddError(
"Invalid Configuration",
"idle_scaling, min_total_memory_gb, max_total_memory_gb, and idle_timeout_minutes must be defined if the service tier is production and idle_scaling is enabled",
"custom managed encryption cannot be defined if the service tier is development",
)
return
}
} else if service.Tier == "production" {
if plan.IdleScaling.ValueBool() && (plan.IdleScaling.IsNull() || plan.MinTotalMemoryGb.IsNull() || plan.MaxTotalMemoryGb.IsNull() || plan.IdleTimeoutMinutes.IsNull()) {
resp.Diagnostics.AddError(
"Invalid Configuration",
"idle_scaling, min_total_memory_gb, max_total_memory_gb, and idle_timeout_minutes must be defined if the service tier is production and idle_scaling is enabled",
)
return
}

if !plan.EncryptionAssumedRoleIdentifier.IsNull() && plan.EncryptionKey.IsNull() {
resp.Diagnostics.AddError(
"Invalid Configuration",
"encryption_assumed_role_identifier cannot be defined without encryption_key as well",
)
return
}

service.IdleScaling = bool(plan.IdleScaling.ValueBool())
if (!plan.EncryptionKey.IsNull() && strings.Compare(plan.CloudProvider.ValueString(), "aws") != 0 ) {
resp.Diagnostics.AddError(
"Invalid Configuration",
"encryption_key and the encryption_assumed_role_identifier is only available for aws services",
)
return
}

if !plan.MinTotalMemoryGb.IsNull() {
minTotalMemoryGb := int(plan.MinTotalMemoryGb.ValueInt64())
service.MinTotalMemoryGb = &minTotalMemoryGb
}
if !plan.MaxTotalMemoryGb.IsNull() {
maxTotalMemoryGb := int(plan.MaxTotalMemoryGb.ValueInt64())
service.MaxTotalMemoryGb = &maxTotalMemoryGb
}
if !plan.IdleTimeoutMinutes.IsNull() {
idleTimeoutMinutes := int(plan.IdleTimeoutMinutes.ValueInt64())
service.IdleTimeoutMinutes = &idleTimeoutMinutes
service.IdleScaling = bool(plan.IdleScaling.ValueBool())

if !plan.MinTotalMemoryGb.IsNull() {
minTotalMemoryGb := int(plan.MinTotalMemoryGb.ValueInt64())
service.MinTotalMemoryGb = &minTotalMemoryGb
}
if !plan.MaxTotalMemoryGb.IsNull() {
maxTotalMemoryGb := int(plan.MaxTotalMemoryGb.ValueInt64())
service.MaxTotalMemoryGb = &maxTotalMemoryGb
}
if !plan.IdleTimeoutMinutes.IsNull() {
idleTimeoutMinutes := int(plan.IdleTimeoutMinutes.ValueInt64())
service.IdleTimeoutMinutes = &idleTimeoutMinutes
}
if !plan.EncryptionKey.IsNull() {
service.EncryptionKey = string(plan.EncryptionKey.ValueString())
}
if !plan.EncryptionAssumedRoleIdentifier.IsNull() {
service.EncryptionAssumedRoleIdentifier = string(plan.EncryptionAssumedRoleIdentifier.ValueString())
}
}
}

if !plan.Password.IsNull() && !plan.PasswordHash.IsNull() {
resp.Diagnostics.AddError(
Expand Down Expand Up @@ -503,6 +543,9 @@ func (r *ServiceResource) Read(ctx context.Context, req resource.ReadRequest, re
"private_dns_hostname": types.StringValue(service.PrivateEndpointConfig.PrivateDnsHostname),
})

state.EncryptionKey = types.StringValue(service.EncryptionKey)
state.EncryptionAssumedRoleIdentifier = types.StringValue(service.EncryptionAssumedRoleIdentifier)

// default null config value to empty string array
if state.PrivateEndpointIds.IsNull() {
state.PrivateEndpointIds = createEmptyList(types.StringType)
Expand Down Expand Up @@ -607,6 +650,22 @@ func (r *ServiceResource) Update(ctx context.Context, req resource.UpdateRequest
)
}

if !plan.EncryptionKey.IsNull() && plan.EncryptionKey != state.EncryptionKey {
resp.Diagnostics.AddAttributeError(
path.Root("encryption_key"),
"Invalid Update",
"ClickHouse does not support changing encryption_key",
)
}

if !plan.EncryptionAssumedRoleIdentifier.IsNull() && plan.EncryptionAssumedRoleIdentifier != state.EncryptionAssumedRoleIdentifier {
resp.Diagnostics.AddAttributeError(
path.Root("encryption_assumed_role_identifier"),
"Invalid Update",
"ClickHouse does not support changing encryption_assumed_role_identifier",
)
}

if config.Tier.ValueString() == "development" {
if !plan.IdleScaling.IsNull() || !plan.MinTotalMemoryGb.IsNull() || !plan.MaxTotalMemoryGb.IsNull() || !plan.IdleTimeoutMinutes.IsNull() {
resp.Diagnostics.AddError(
Expand Down

0 comments on commit 0937bc5

Please sign in to comment.