Skip to content

Commit

Permalink
[CC-8720]CMEK resource
Browse files Browse the repository at this point in the history
This commit adds a new CMEK resource, which primarily manages the
configuration of customer-managed encryption keys (CMEK). CMEK is
enabled for a cluster when the resource is created, and keys can
be rotated by updating their specs.

Due to circular dependencies (new regions depend on CMEK config,
which depends on role policy, which depends on cluster), new
regions must be managed by the CMEK resource. That means the cluster
resource and CMEK resource need to keep track of which regions they
"own" and reconcile that with updates and the actual state of the
cluster. That's the bulk of the complexity here.

Destroying a CMEK resource is a no-op, since CMEK cannot be disabled.
That means that a user could be left with "floating" regions.
I need to figure out a way to block targeted destroy operations on
CMEK resources while allowing them to be removed from state when the
parent cluster is destroyed. We could attempt to remove additional
regions on destroy, but that would take significantly longer.

Happy to do a walkthrough and discuss tradeoffs at a watercooler.
  • Loading branch information
erademacher committed Dec 21, 2022
1 parent 5e55c84 commit 0894069
Show file tree
Hide file tree
Showing 13 changed files with 1,279 additions and 112 deletions.
5 changes: 3 additions & 2 deletions docs/data-sources/cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
page_title: "cockroach_cluster Data Source - terraform-provider-cockroach"
subcategory: ""
description: |-
clusterSourceType Data Source
Cluster Data Source
---

# cockroach_cluster (Data Source)

clusterSourceType Data Source
Cluster Data Source



Expand Down Expand Up @@ -39,6 +39,7 @@ Read-Only:
- `machine_type` (String)
- `memory_gib` (Number)
- `num_virtual_cpus` (Number)
- `private_network_visibility` (Boolean)
- `storage_gib` (Number)


Expand Down
1 change: 1 addition & 0 deletions docs/resources/cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Optional:
- `disk_iops` (Number)
- `machine_type` (String)
- `num_virtual_cpus` (Number)
- `private_network_visibility` (Boolean) Set to true to assign private IP addresses to nodes. Required for CMEK, PrivateLink, and other advanced features.
- `storage_gib` (Number)

Read-Only:
Expand Down
77 changes: 77 additions & 0 deletions docs/resources/cmek.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "cockroach_cmek Resource - terraform-provider-cockroach"
subcategory: ""
description: |-
Customer-managed encryption keys (CMEK) resource for a single cluster
---

# cockroach_cmek (Resource)

Customer-managed encryption keys (CMEK) resource for a single cluster



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `id` (String) Cluster ID
- `regions` (Attributes List) (see [below for nested schema](#nestedatt--regions))

### Optional

- `additional_regions` (Attributes List) Once CMEK is enabled for a cluster, no new regions can be added to the cluster resource, since they need encryption key info stored in the CMEK resource. New regions can be added and maintained here instead. (see [below for nested schema](#nestedatt--additional_regions))

### Read-Only

- `status` (String) Aggregated status of the cluster's encryption key(s)

<a id="nestedatt--regions"></a>
### Nested Schema for `regions`

Required:

- `key` (Attributes) (see [below for nested schema](#nestedatt--regions--key))
- `region` (String)

Read-Only:

- `status` (String)

<a id="nestedatt--regions--key"></a>
### Nested Schema for `regions.key`

Required:

- `auth_principal` (String)
- `type` (String) Current allowed values are 'AWS_KMS' and 'GCP_CLOUD_KMS'
- `uri` (String)

Read-Only:

- `created_at` (String)
- `status` (String)
- `updated_at` (String)
- `user_message` (String)



<a id="nestedatt--additional_regions"></a>
### Nested Schema for `additional_regions`

Required:

- `name` (String)

Optional:

- `node_count` (Number)

Read-Only:

- `sql_dns` (String)
- `ui_dns` (String)


170 changes: 170 additions & 0 deletions examples/workflows/cockroach_cmek/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# Your Organization ID can be found at https://cockroachlabs.cloud/information
variable "org_id" {
type = string
nullable = false
}

# Required to assign yourself permission to update the key.
variable "iam_user" {
type = string
nullable = false
}

variable "cluster_name" {
type = string
nullable = false
}

variable "aws_region" {
type = string
nullable = false
default = "us-west2"
}

variable "additional_regions" {
type = list(string)
nullable = false
}

variable "cluster_node_count" {
type = number
nullable = false
default = 3
}

variable "storage_gib" {
type = number
nullable = false
default = 15
}

variable "machine_type" {
type = string
nullable = false
default = "m5.large"
}

terraform {
required_providers {
cockroach = {
source = "cockroachdb/cockroach"
}
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
provider "cockroach" {
# export COCKROACH_API_KEY with the cockroach cloud API Key
}

provider "aws" {
# See https://registry.terraform.io/providers/hashicorp/aws/latest/docs
# for configuration steps.

# Please don't use a variable for region in production! The AWS provider won't
# be able to find any resources if this value changes and you'll get
# into a weird state. Be sure to run `terraform destroy` before changing
# this value.
region = var.aws_region
}

resource "cockroach_cluster" "example" {
name = var.cluster_name
cloud_provider = "AWS"
dedicated = {
storage_gib = var.storage_gib
machine_type = var.machine_type
private_network_visibility = true
}
regions = [{
name = var.aws_region,
node_count = var.cluster_node_count
}
]
}

resource "aws_iam_role" "example" {
name = "cmek_test_role"

assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : "sts:AssumeRole",
"Principal" : {
"AWS" : cockroach_cluster.example.account_id
},
"Condition" : {
"StringEquals" : {
"sts:ExternalId" : var.org_id
}
}
}
]
})
}

data "aws_iam_user" "example" {
user_name = var.iam_user
}

resource "aws_kms_key" "example" {
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : "kms:*",
"Principal" : {
"AWS" : [
aws_iam_role.example.arn,
data.aws_iam_user.example.arn
]
},
"Resource" : "*"
}
]
})
multi_region = true
}

resource "cockroach_cmek" "example" {
id = cockroach_cluster.example.id
regions = /*concat(*/[
{
region : var.aws_region
key : {
auth_principal : aws_iam_role.example.arn
type : "AWS_KMS"
uri : aws_kms_key.example.arn
}
}
]#,
#
# Additional regions can be added after CMEK is enabled by updating
# the `region` attribute and adding their name and node count to
# `additional_regions`. These regions will be managed separately from
# the parent cluster, but will otherwise behave the same. Cluster data
# sources will always show the entire list of regions, regardless of
# whether they're managed by the cluster or CMEK resource.
#
# These should be concatenated with the current region(s).
#[for r in var.additional_regions : {
# region: r,
# key: {
# auth_principal: aws_iam_role.example.arn
# type: "AWS_KMS"
# uri: aws_kms_key.example.arn
# }
#}])

#additional_regions = [for r in var.additional_regions :
# {
# name = r
# node_count = var.cluster_node_count
# }
#]
}
Loading

0 comments on commit 0894069

Please sign in to comment.