From 78ec7d9ed9911f078888cbe695d17017dd6a7fa7 Mon Sep 17 00:00:00 2001 From: Nicolas Lamirault Date: Sun, 14 Nov 2021 16:25:33 +0100 Subject: [PATCH 1/3] Update: precommit configuration Signed-off-by: Nicolas Lamirault --- .pre-commit-config.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6e77494..77d07a0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,11 +23,12 @@ repos: - id: check-yaml - id: check-added-large-files - repo: git://github.com/antonbabenko/pre-commit-terraform - rev: v1.50.0 + rev: v1.56.0 hooks: - id: terraform_fmt - id: terraform_docs - id: terraform_tflint + files: \.tf$ args: - '--args=--enable-rule=terraform_deprecated_interpolation' - '--args=--enable-rule=terraform_deprecated_index' @@ -42,3 +43,5 @@ repos: - '--args=--enable-rule=terraform_unused_required_providers' - '--args=--enable-rule=terraform_standard_module_structure' - id: terraform_tfsec + args: + - '--args=--config-file __GIT_WORKING_DIR__/.tfsec.yml' From a8776fa4559ca64571dd767646efb821474357f3 Mon Sep 17 00:00:00 2001 From: Nicolas Lamirault Date: Sun, 14 Nov 2021 19:34:06 +0100 Subject: [PATCH 2/3] Update: Refactoring using Google modules Signed-off-by: Nicolas Lamirault --- .tfsec.yml | 16 +++++++++ README.md | 51 ++++++++++++++++++++++++++- kms.tf | 15 +++++--- locals.tf | 2 +- main.tf | 2 +- outputs.tf | 2 +- variables.tf | 36 +++++++++++++++++++ velero.tf | 98 ++++++++++++++++++++++++++++++++++------------------ 8 files changed, 180 insertions(+), 42 deletions(-) create mode 100644 .tfsec.yml diff --git a/.tfsec.yml b/.tfsec.yml new file mode 100644 index 0000000..bbfb7b2 --- /dev/null +++ b/.tfsec.yml @@ -0,0 +1,16 @@ +# Copyright (C) 2021 Nicolas Lamirault +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +exclude: diff --git a/README.md b/README.md index c17ab5d..07fbca6 100644 --- a/README.md +++ b/README.md @@ -49,5 +49,54 @@ keyring_location = "europe-west1" ## Documentation - +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0 | +| [google](#requirement\_google) | >= 3.54.0 | + +## Providers + +| Name | Version | +|------|---------| +| [google](#provider\_google) | >= 3.54.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [bucket](#module\_bucket) | terraform-google-modules/cloud-storage/google//modules/simple_bucket | 3.0.0 | +| [custom](#module\_custom) | terraform-google-modules/iam/google//modules/custom_role_iam | 7.3.0 | +| [iam](#module\_iam) | terraform-google-modules/iam/google//modules/service_accounts_iam | 7.3.0 | +| [service\_account](#module\_service\_account) | terraform-google-modules/service-accounts/google | 4.0.3 | + +## Resources + +| Name | Type | +|------|------| +| [google_kms_crypto_key.velero](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/kms_crypto_key) | resource | +| [google_kms_crypto_key_iam_binding.binding](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/kms_crypto_key_iam_binding) | resource | +| [google_kms_key_ring.velero](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/kms_key_ring) | resource | +| [google_storage_project_service_account.gcs_account](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/storage_project_service_account) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [bucket\_labels](#input\_bucket\_labels) | Map of labels to apply to the bucket | `map(string)` |
{
"made-by": "terraform"
}
| no | +| [bucket\_location](#input\_bucket\_location) | The bucket location | `string` | n/a | yes | +| [bucket\_storage\_class](#input\_bucket\_storage\_class) | Bucket storage class. | `string` | `"MULTI_REGIONAL"` | no | +| [enable\_kms](#input\_enable\_kms) | Enable custom KMS key | `bool` | n/a | yes | +| [keyring\_location](#input\_keyring\_location) | The KMS keyring location | `string` | n/a | yes | +| [lifecycle\_rules](#input\_lifecycle\_rules) | The bucket's Lifecycle Rules configuration. |
list(object({
# Object with keys:
# - type - The type of the action of this Lifecycle Rule. Supported values: Delete and SetStorageClass.
# - storage_class - (Required if action type is SetStorageClass) The target Storage Class of objects affected by this Lifecycle Rule.
action = any

# Object with keys:
# - age - (Optional) Minimum age of an object in days to satisfy this condition.
# - created_before - (Optional) Creation date of an object in RFC 3339 (e.g. 2017-06-13) to satisfy this condition.
# - with_state - (Optional) Match to live and/or archived objects. Supported values include: "LIVE", "ARCHIVED", "ANY".
# - matches_storage_class - (Optional) Storage Class of objects to satisfy this condition. Supported values include: MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, STANDARD, DURABLE_REDUCED_AVAILABILITY.
# - num_newer_versions - (Optional) Relevant only for versioned objects. The number of newer versions of an object to satisfy this condition.
condition = any
}))
|
[
{
"action": {
"type": "Delete"
},
"condition": {
"age": 365,
"with_state": "ANY"
}
}
]
| no | +| [namespace](#input\_namespace) | The Kubernetes namespace | `string` | n/a | yes | +| [project](#input\_project) | The project in which the resource belongs | `string` | n/a | yes | +| [service\_account](#input\_service\_account) | The Kubernetes service account | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [service\_account](#output\_service\_account) | Service Account for Velero | diff --git a/kms.tf b/kms.tf index d7d09a8..0e57d6e 100644 --- a/kms.tf +++ b/kms.tf @@ -13,13 +13,15 @@ # limitations under the License. resource "google_kms_key_ring" "velero" { - name = local.service_name + count = var.enable_kms ? 1 : 0 + name = local.service location = var.keyring_location } resource "google_kms_crypto_key" "velero" { - name = local.service_name - key_ring = google_kms_key_ring.velero.id + count = var.enable_kms ? 1 : 0 + name = local.service + key_ring = google_kms_key_ring.velero[0].id rotation_period = "100000s" # lifecycle { @@ -31,8 +33,11 @@ data "google_storage_project_service_account" "gcs_account" { } resource "google_kms_crypto_key_iam_binding" "binding" { - crypto_key_id = google_kms_crypto_key.velero.id + count = var.enable_kms ? 1 : 0 + crypto_key_id = google_kms_crypto_key.velero[0].id role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - members = ["serviceAccount:${data.google_storage_project_service_account.gcs_account.email_address}"] + members = [ + "serviceAccount:${data.google_storage_project_service_account.gcs_account.email_address}" + ] } diff --git a/locals.tf b/locals.tf index 1867f9e..9255529 100644 --- a/locals.tf +++ b/locals.tf @@ -13,5 +13,5 @@ # limitations under the License. locals { - service_name = format("%s-velero", var.project) + service = "velero" } diff --git a/main.tf b/main.tf index 20760ab..8d8bf4b 100644 --- a/main.tf +++ b/main.tf @@ -13,7 +13,7 @@ # limitations under the License. terraform { - required_version = ">= 0.14.0" + required_version = ">= 1.0.0" required_providers { google = { diff --git a/outputs.tf b/outputs.tf index f13bdce..d62a6d0 100644 --- a/outputs.tf +++ b/outputs.tf @@ -14,5 +14,5 @@ output "service_account" { description = "Service Account for Velero" - value = google_service_account.velero.email + value = module.service_account.email } diff --git a/variables.tf b/variables.tf index 0c01ba2..c6c4051 100644 --- a/variables.tf +++ b/variables.tf @@ -43,6 +43,33 @@ variable "bucket_labels" { } } +variable "lifecycle_rules" { + description = "The bucket's Lifecycle Rules configuration." + type = list(object({ + # Object with keys: + # - type - The type of the action of this Lifecycle Rule. Supported values: Delete and SetStorageClass. + # - storage_class - (Required if action type is SetStorageClass) The target Storage Class of objects affected by this Lifecycle Rule. + action = any + + # Object with keys: + # - age - (Optional) Minimum age of an object in days to satisfy this condition. + # - created_before - (Optional) Creation date of an object in RFC 3339 (e.g. 2017-06-13) to satisfy this condition. + # - with_state - (Optional) Match to live and/or archived objects. Supported values include: "LIVE", "ARCHIVED", "ANY". + # - matches_storage_class - (Optional) Storage Class of objects to satisfy this condition. Supported values include: MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, STANDARD, DURABLE_REDUCED_AVAILABILITY. + # - num_newer_versions - (Optional) Relevant only for versioned objects. The number of newer versions of an object to satisfy this condition. + condition = any + })) + default = [{ + action = { + type = "Delete" + } + condition = { + age = 365 + with_state = "ANY" + } + }] +} + # Workload Identity variable "namespace" { @@ -55,6 +82,15 @@ variable "service_account" { description = "The Kubernetes service account" } +# +# KMS +# + +variable "enable_kms" { + type = bool + description = "Enable custom KMS key" +} + variable "keyring_location" { type = string description = "The KMS keyring location" diff --git a/velero.tf b/velero.tf index 3a52978..ad69641 100644 --- a/velero.tf +++ b/velero.tf @@ -14,28 +14,28 @@ # Doc: https://github.com/vmware-tanzu/velero-plugin-for-gcp#setup -resource "google_service_account" "velero" { - account_id = local.service_name - display_name = "Velero" - description = "Created by Terraform" -} - -resource "google_storage_bucket" "velero" { - name = local.service_name - location = var.bucket_location - storage_class = var.bucket_storage_class - labels = var.bucket_labels +module "service_account" { + source = "terraform-google-modules/service-accounts/google" + version = "4.0.3" - encryption { - default_kms_key_name = google_kms_crypto_key.velero.id - } + project_id = var.project - # Ensure the KMS crypto-key IAM binding for the service account exists prior to the - # bucket attempting to utilise the crypto-key. - depends_on = [google_kms_crypto_key_iam_binding.binding] + names = [ + local.service + ] } -resource "google_project_iam_custom_role" "velero" { +module "custom" { + source = "terraform-google-modules/iam/google//modules/custom_role_iam" + version = "7.3.0" + + target_level = "project" + target_id = var.project + role_id = local.service + title = local.service + description = format("Role for %s", local.service) + base_roles = [] + permissions = [ "compute.disks.get", "compute.disks.create", @@ -46,25 +46,57 @@ resource "google_project_iam_custom_role" "velero" { "compute.snapshots.delete", "compute.zones.get" ] - role_id = "velero" - title = "Velero" + + excluded_permissions = [] + + members = [] + # members = [ + # format("serviceAccount:%s", module.service_account.email), + # ] } -resource "google_project_iam_binding" "velero" { - role = google_project_iam_custom_role.velero.id - members = [ - format("serviceAccount:%s", google_service_account.velero.email) +module "iam" { + source = "terraform-google-modules/iam/google//modules/service_accounts_iam" + version = "7.3.0" + + project = var.project + + service_accounts = [ + module.service_account.email ] -} + mode = "authoritative" + + bindings = { + "roles/velero" = [ + format("serviceAccount:%s", module.service_account.email), + ] + "roles/iam.workloadIdentityUser" = [ + format("serviceAccount:%s.svc.id.goog[%s/%s]", var.project, var.namespace, var.service_account) + ] + } -resource "google_storage_bucket_iam_member" "velero" { - bucket = google_storage_bucket.velero.name - role = "roles/storage.objectAdmin" - member = format("serviceAccount:%s", google_service_account.velero.email) + # depends_on = [module.service_account] } -resource "google_service_account_iam_member" "velero" { - role = "roles/iam.workloadIdentityUser" - service_account_id = google_service_account.velero.name - member = format("serviceAccount:%s.svc.id.goog[%s/%s]", var.project, var.namespace, var.service_account) +module "bucket" { + source = "terraform-google-modules/cloud-storage/google//modules/simple_bucket" + version = "3.0.0" + + name = format("%s-%s", var.project, local.service) + project_id = var.project + location = var.bucket_location + storage_class = var.bucket_storage_class + labels = var.bucket_labels + lifecycle_rules = var.lifecycle_rules + + encryption = var.enable_kms ? { + default_kms_key_name = google_kms_crypto_key.velero[0].name + } : null + + iam_members = [{ + role = "roles/storage.objectAdmin" + member = format("serviceAccount:%s", module.service_account.email) + }] + + # depends_on = [module.service_account] } From 53b6233f3e069e44d952304dc990efcce47c0797 Mon Sep 17 00:00:00 2001 From: Nicolas Lamirault Date: Wed, 17 Nov 2021 08:39:13 +0100 Subject: [PATCH 3/3] Update: Refactoring modules Signed-off-by: Nicolas Lamirault --- README.md | 5 +++-- velero.tf | 43 +++++++++++++++++++++++++------------------ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 07fbca6..6398e7c 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,9 @@ keyring_location = "europe-west1" | Name | Source | Version | |------|--------|---------| | [bucket](#module\_bucket) | terraform-google-modules/cloud-storage/google//modules/simple_bucket | 3.0.0 | -| [custom](#module\_custom) | terraform-google-modules/iam/google//modules/custom_role_iam | 7.3.0 | -| [iam](#module\_iam) | terraform-google-modules/iam/google//modules/service_accounts_iam | 7.3.0 | +| [custom\_role](#module\_custom\_role) | terraform-google-modules/iam/google//modules/custom_role_iam | 7.3.0 | +| [iam\_service\_accounts](#module\_iam\_service\_accounts) | terraform-google-modules/iam/google//modules/service_accounts_iam | 7.3.0 | +| [iam\_storage\_buckets](#module\_iam\_storage\_buckets) | terraform-google-modules/iam/google//modules/storage_buckets_iam | 7.3.0 | | [service\_account](#module\_service\_account) | terraform-google-modules/service-accounts/google | 4.0.3 | ## Resources diff --git a/velero.tf b/velero.tf index ad69641..164a6c1 100644 --- a/velero.tf +++ b/velero.tf @@ -25,14 +25,14 @@ module "service_account" { ] } -module "custom" { +module "custom_role" { source = "terraform-google-modules/iam/google//modules/custom_role_iam" version = "7.3.0" target_level = "project" target_id = var.project role_id = local.service - title = local.service + title = title(local.service) description = format("Role for %s", local.service) base_roles = [] @@ -49,33 +49,27 @@ module "custom" { excluded_permissions = [] - members = [] - # members = [ - # format("serviceAccount:%s", module.service_account.email), - # ] + members = [ + format("serviceAccount:%s", module.service_account.email), + ] } -module "iam" { +module "iam_service_accounts" { source = "terraform-google-modules/iam/google//modules/service_accounts_iam" version = "7.3.0" project = var.project + mode = "authoritative" service_accounts = [ module.service_account.email ] - mode = "authoritative" bindings = { - "roles/velero" = [ - format("serviceAccount:%s", module.service_account.email), - ] "roles/iam.workloadIdentityUser" = [ format("serviceAccount:%s.svc.id.goog[%s/%s]", var.project, var.namespace, var.service_account) ] } - - # depends_on = [module.service_account] } module "bucket" { @@ -93,10 +87,23 @@ module "bucket" { default_kms_key_name = google_kms_crypto_key.velero[0].name } : null - iam_members = [{ - role = "roles/storage.objectAdmin" - member = format("serviceAccount:%s", module.service_account.email) - }] + # https://github.com/terraform-google-modules/terraform-google-cloud-storage/issues/142 + # iam_members = [{ + # role = "roles/storage.objectAdmin" + # member = format("serviceAccount:%s", module.service_account.email) + # }] +} + +module "iam_storage_buckets" { + source = "terraform-google-modules/iam/google//modules/storage_buckets_iam" + version = "7.3.0" + + storage_buckets = [module.bucket.bucket.name] + mode = "authoritative" - # depends_on = [module.service_account] + bindings = { + "roles/storage.objectAdmin" = [ + format("serviceAccount:%s", module.service_account.email) + ] + } }