diff --git a/blueprints/secops/README.md b/blueprints/secops/README.md index 0d42455f6..04082de5d 100644 --- a/blueprints/secops/README.md +++ b/blueprints/secops/README.md @@ -2,6 +2,13 @@ This repository provides a collection of Terraform blueprints designed to automate the implementation of custom integrations, agents and configurations for Google Cloud Security and Operations SecOps (aka Chronicle). +## BindPlane OP Management on GKE + + This [blueprint](./bindplane-gke/) is a modular and scalable solution for deployment of the BindPlane OP Management Console within a Google Kubernetes Engine (GKE) environment. + +
+ + ## SecOps GKE Forwarder This [blueprint](./secops-gke-forwarder/) is a modular and scalable solution for setting up a SecOps forwarder on Google Kubernetes Engine (GKE). This forwarder is designed to handle multi-tenant data ingestion, ensuring secure and efficient log forwarding to your SecOps SIEM instances. diff --git a/blueprints/secops/bindplane-gke/OWNERS b/blueprints/secops/bindplane-gke/OWNERS new file mode 100644 index 000000000..65c8fc162 --- /dev/null +++ b/blueprints/secops/bindplane-gke/OWNERS @@ -0,0 +1 @@ +simonebruzzechesse diff --git a/blueprints/secops/bindplane-gke/README.md b/blueprints/secops/bindplane-gke/README.md new file mode 100644 index 000000000..85de48b36 --- /dev/null +++ b/blueprints/secops/bindplane-gke/README.md @@ -0,0 +1,162 @@ +# BindPlane OP Management console on GKE + +This Terraform module simplifies the deployment of the BindPlane OP Management Console within a Google Kubernetes Engine (GKE) environment. It's specifically engineered for organizations seeking a scalable and highly available solution, capitalizing on the strengths of containerization and managed platform services like Cloud SQL for PostgreSQL. + +This module streamlines the process of deploying BindPlane OP, by leveraging GKE, PubSub and Cloud SQL, this module provides: + +- **Simplified Deployment**: Deploy a production-ready BindPlane OP environment with minimal manual configuration. +- **Enhanced Scalability**: Easily adapt to increasing demands and data volumes as your needs evolve. +- **Increased Resilience**: Benefit from the high availability and fault tolerance offered by GKE and Cloud SQL. +- **Operational Efficiency**: Reduce operational overhead by utilizing managed Kubernetes and database services. + +This module encapsulates best practices for deploying BindPlane OP in a cloud-native environment, ensuring a robust and reliable foundation for your observability platform. + +### High level architecture + +The following diagram illustrates the high-level design of created resources, which can be adapted to specific requirements via variables: + +![Bindplane OP Management console on GKE](./images/diagram.png) + +BindPlane OP Management console will be exposed via Internal HTTPS Load Balancer, this module assume a private connection to GCP environment is in place to reach the BindPlane management console over private IPs. +In case no private connection is in place it should be pretty straightforward to setup a proxy VM to proxy the connection towards the bindplane console. Of course such a deployment can only deal with agents running on the same GCP infrastructure. + +### Deployment + +#### Step 0: Cloning the repository + +If you want to deploy from your Cloud Shell, click on the image below, sign in +if required and when the prompt appears, click on “confirm”. + +[![Open Cloudshell](./images/cloud-shell-button.png)](https://shell.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2FGoogleCloudPlatform%2Fcloud-foundation-fabric&cloudshell_workspace=blueprints%2Fthird-party-solutions%2Fwordpress%2Fcloudrun) + +Otherwise, in your console of choice: + +```bash +git clone https://github.com/GoogleCloudPlatform/cloud-foundation-fabric.git +``` + +Before you deploy the architecture, you will need at least the following +information/configurations in place (for more precise configuration see the Variables section): + +* The project ID +* The VPC host project +* VPC and subnets should already exist +* Subnet must be configured with pods and services secondary ranges (default names for secondary ranges is "pod" and "services") + +#### Step 2: Prepare the variables + +Once you have the required information, head back to your cloned repository. +Make sure you’re in the directory of this tutorial (where this README is in). + +Configure the Terraform variables in your `terraform.tfvars` file. +See the example test at the end of this README.md as starting point - just +copy it to `terraform.tfvars` and edit the latter. See the variables +documentation below. + +> **Warning** +> +> BindPlane secrets (such as license and admin password) specified as variables within this Terraform configuration will be stored in plain text within the Terraform state file. + +#### Step 3: Prepare the providers in the root module + +Setup terraform providers in the root module to deal with kubernetes resources as follows: + +```terraform +data "google_client_config" "identity" { + count = module.bindplane-gke.fleet_host != null ? 1 : 0 +} + +provider "kubernetes" { + host = module.bindplane-gke.fleet_host + token = try(data.google_client_config.identity.0.access_token, null) +} + +provider "kubectl" { + host = module.bindplane-gke.fleet_host + token = try(data.google_client_config.identity.0.access_token, null) +} +``` + +#### Step 4: Deploy resources + +Initialize your Terraform environment and deploy the resources: + +```shell +terraform init +terraform apply +``` + +Get kubeconfig to connect to the cluster using the command below: + +```shell +gcloud container fleet memberships get-credentials CLUSTER_NAME --project PROJECT +``` + +Then running the command `kubectl get pods` you should receive the following message: + +``` +"No resources found in default namespace." +``` + +In case private connection is available and DNS configuration is properly in place you should be able to reach the BindPlane OP Management console navigating the url (e.g. https://bindplane.example.com/), the following login page should show up. + +![Bindplane OP Management console login page](./images/login.png) + +Access the management console leveraging credentials bootstrapped via terraform (user and password in `bindplane_secrets` variable). + +## Variables + +| name | description | type | required | default | +|---|---|:---:|:---:|:---:| +| [bindplane_secrets](variables.tf#L26) | Bindplane secrets. | object({…}) | ✓ | | +| [network_config](variables.tf#L57) | Shared VPC network configurations to use for GKE cluster. | object({…}) | ✓ | | +| [prefix](variables.tf#L79) | Prefix used for resource names. | string | ✓ | | +| [project_id](variables.tf#L98) | Project id, references existing project if `project_create` is null. | string | ✓ | | +| [region](variables.tf#L103) | GCP region. | string | ✓ | | +| [bindplane_config](variables.tf#L17) | Bindplane config. | object({…}) | | {} | +| [cluster_config](variables.tf#L36) | GKE cluster configuration. | object({…}) | | {} | +| [dns_config](variables.tf#L47) | DNS config. | object({…}) | | {} | +| [postgresql_config](variables.tf#L69) | Cloud SQL postgresql config. | object({…}) | | {} | +| [project_create](variables.tf#L89) | Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | object({…}) | | null | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| [bindplane_hostname](outputs.tf#L17) | BindPlane OP Management console hostname. | | +| [ca_cert](outputs.tf#L22) | TLS CA certificate. | | +| [cluster_ca_certificate](outputs.tf#L27) | GKE CA Certificate. | | +| [fleet_host](outputs.tf#L32) | GKE Fleet host. | | +| [lb_ip_address](outputs.tf#L37) | Ingress LB address. | | + +## Test + +```hcl +module "bindplane-gke" { + source = "./fabric/blueprints/secops/bindplane-gke" + project_id = "test" + project_create = { + billing_account_id = "12345-ABCDEF-12345" + parent = "folders/2345678901" + } + bindplane_secrets = { + user = "admin" + password = "thisisnotasecret" + sessions_secret = "xxxxxx-xxxxxxx-xxxxxx" + license = "XXXXXXXXXXXXXXXXXXXXXX" + } + dns_config = { + bootstrap_private_zone = true + domain = "example.com" + hostname = "bindplane" + } + network_config = { + network_self_link = "https://www.googleapis.com/compute/v1/projects/prod-net-landing-0/global/networks/prod-landing-0" + subnet_self_link = "https://www.googleapis.com/compute/v1/projects/prod-net-landing-0/regions/europe-west1/subnetworks/gke" + ip_range_gke_master = "192.168.0.0/28" + } + region = "europe-west8" + prefix = "tmp" +} +# tftest modules=10 resources=45 +``` diff --git a/blueprints/secops/bindplane-gke/bindplane-deployment/main.tf b/blueprints/secops/bindplane-gke/bindplane-deployment/main.tf new file mode 100644 index 000000000..abdeb4de1 --- /dev/null +++ b/blueprints/secops/bindplane-gke/bindplane-deployment/main.tf @@ -0,0 +1,59 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +locals { + bindplane_password = coalesce(var.bindplane_secrets.password, try(random_password.password.0.result, null)) +} + +resource "random_password" "password" { + count = var.bindplane_secrets.password == null ? 1 : 0 + length = 16 + special = true + override_special = "_!%^" +} + +resource "kubernetes_namespace" "namespace" { + metadata { + name = "bindplane" + } +} + +resource "kubernetes_secret" "bindplane_secret" { + metadata { + name = "bindplane" + namespace = kubernetes_namespace.namespace.metadata[0].name + } + + data = { + username = var.bindplane_secrets.user + password = local.bindplane_password + sessions_secret = var.bindplane_secrets.sessions_secret + license = var.bindplane_secrets.license + } + type = "Opaque" +} + +resource "kubernetes_secret" "tls" { + metadata { + name = "bindplane-tls" + namespace = kubernetes_namespace.namespace.metadata[0].name + } + data = { + "tls.crt" = var.bindplane_tls.cer + "tls.key" = var.bindplane_tls.key + } + type = "kubernetes.io/tls" +} diff --git a/blueprints/secops/bindplane-gke/bindplane-deployment/variables.tf b/blueprints/secops/bindplane-gke/bindplane-deployment/variables.tf new file mode 100644 index 000000000..4d15bfacf --- /dev/null +++ b/blueprints/secops/bindplane-gke/bindplane-deployment/variables.tf @@ -0,0 +1,33 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +variable "bindplane_secrets" { + description = "Bindplane configuration." + type = object({ + license = string + user = optional(string, "admin") + password = optional(string, null) + sessions_secret = string + }) +} + +variable "bindplane_tls" { + description = "Bindplane TLS certificates." + type = object({ + cer = string + key = string + }) +} diff --git a/blueprints/secops/bindplane-gke/config/values.yaml.tpl b/blueprints/secops/bindplane-gke/config/values.yaml.tpl new file mode 100644 index 000000000..a6098a935 --- /dev/null +++ b/blueprints/secops/bindplane-gke/config/values.yaml.tpl @@ -0,0 +1,84 @@ +# This ingress example uses Ingress NGINX and Cert Manager +# for creating Lets Encrypt signed certificates. +# +# - https://kubernetes.github.io/ingress-nginx/deploy/#gce-gke +# - https://cert-manager.io/docs/tutorials/getting-started-with-cert-manager-on-google-kubernetes-engine-using-lets-encrypt-for-ingress-ssl/ +# +ingress: + enable: true + host: ${hostname} + class: "gce-internal" + tls: + enable: true + secret: bindplane-tls + annotations: + # cert-manager.io/issuer: letsencrypt + kubernetes.io/ingress.regional-static-ip-name: ${address} + +config: + # Use the secret named "bindplane", which contains + # the license, username, password, secret_key, and sessions_secret. + # If you do not want to use a secret, see the comment below and + # disable this option. + licenseUseSecret: true + + # Defaults to wss://bindplane.bindplane.svc.cluster.local:3001/v1/opamp, + # which is the bindplane namespace's bindplane service. This is suitable + # for connecting agents within the same cluster. We are using ingress + # so server_url needs to be updated to the ingress host. + # NOTE: server_url maps to bindplane's network.remoteURL option. + server_url: https://${hostname} + +# Fixed number of pods. BindPlane CPU usage is bursty, using +# a pod autoscaler can be tricky. Generally a fixed number +# of pods is recommended. +replicas: 2 + +resources: + # Allow cpu bursting by leaving limits.cpu unset + requests: + cpu: '1000m' + memory: '4096Mi' + limits: + memory: '4096Mi' + +# Node pools must be authenticated to Pub/Sub with one of the following options +# - Pub/Sub scope enabled +# - GKE Service Account with Pub/Sub permissions +# - Service Account key file and the GOOGLE_APPLICATION_CREDENTIALS environment variable set +# to the path of the key file. You can use extraVolumes, extraVolumeMounts, extraEnv to +# mount a configMap or secret containing the key file. +eventbus: + type: 'pubsub' + pubsub: + projectid: '${gcp_project_id}' + topic: 'bindplane' + +backend: + type: postgres + postgres: + host: '${postgresql_ip}' + port: 5432 + database: 'bindplane' + username: '${postgresql_username}' + password: '${postgresql_password}' + # Replicas * max connections should not exceed + # your Postgres instance's max connections. + # This option defaults to 100, which is too high + # for an environment with 7 replicas. + maxConnections: 20 + +transform_agent: + replicas: 2 + +# Prometheus is deployed and managed by the Helm chart. At scale +# it will require additional resources which can be set here. +prometheus: + resources: + requests: + cpu: '2000m' + memory: '8192Mi' + limits: + memory: '8192Mi' + storage: + volumeSize: '120Gi' diff --git a/blueprints/secops/bindplane-gke/images/cloud-shell-button.png b/blueprints/secops/bindplane-gke/images/cloud-shell-button.png new file mode 100644 index 000000000..21a3f3de9 Binary files /dev/null and b/blueprints/secops/bindplane-gke/images/cloud-shell-button.png differ diff --git a/blueprints/secops/bindplane-gke/images/diagram.png b/blueprints/secops/bindplane-gke/images/diagram.png new file mode 100644 index 000000000..ff1902c17 Binary files /dev/null and b/blueprints/secops/bindplane-gke/images/diagram.png differ diff --git a/blueprints/secops/bindplane-gke/images/login.png b/blueprints/secops/bindplane-gke/images/login.png new file mode 100644 index 000000000..2681ce887 Binary files /dev/null and b/blueprints/secops/bindplane-gke/images/login.png differ diff --git a/blueprints/secops/bindplane-gke/main.tf b/blueprints/secops/bindplane-gke/main.tf new file mode 100644 index 000000000..4e0b12c34 --- /dev/null +++ b/blueprints/secops/bindplane-gke/main.tf @@ -0,0 +1,224 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +locals { + fleet_host = join("", [ + "https://connectgateway.googleapis.com/v1/", + "projects/${module.project.number}/", + "locations/global/gkeMemberships/bindplane" + ]) +} + +module "project" { + source = "../../../modules/project" + billing_account = (var.project_create != null + ? var.project_create.billing_account_id + : null + ) + parent = (var.project_create != null + ? var.project_create.parent + : null + ) + prefix = var.prefix + project_create = var.project_create != null + name = var.project_id + services = concat([ + "compute.googleapis.com", + "iap.googleapis.com", + "stackdriver.googleapis.com", + "chronicle.googleapis.com", + "container.googleapis.com", + "gkehub.googleapis.com", + "connectgateway.googleapis.com", + "gkeconnect.googleapis.com" + ]) + iam = { + "roles/pubsub.editor" = ["principal://iam.googleapis.com/projects/${module.project.number}/locations/global/workloadIdentityPools/${module.project.project_id}.svc.id.goog/subject/ns/bindplane/sa/bindplane"] + } +} + +module "fleet" { + source = "../../../modules/gke-hub" + project_id = module.project.project_id + clusters = { + "bindplane" = module.bindplane-cluster.id + } +} + +module "bindplane-cluster" { + source = "../../../modules/gke-cluster-autopilot" + project_id = module.project.project_id + name = var.cluster_config.cluster_name + location = var.region + deletion_protection = false + vpc_config = { + network = var.network_config.network_self_link + subnetwork = var.network_config.subnet_self_link + secondary_range_names = { + pods = var.network_config.secondary_pod_range_name + services = var.network_config.secondary_services_range_name + } + master_ipv4_cidr_block = var.network_config.ip_range_gke_master + master_authorized_ranges = var.cluster_config.master_authorized_ranges + } + access_config = { + dns_access = false + ip_access = { + authorized_ranges = { + "rfc-1918-10-8" = "10.0.0.0/8" + } + private_endpoint_config = { + global_access = true + } + } + } + enable_features = { + gateway_api = true + } + logging_config = { + enable_api_server_logs = true + enable_scheduler_logs = true + enable_controller_manager_logs = true + } + monitoring_config = { + enable_daemonset_metrics = true + enable_deployment_metrics = true + enable_hpa_metrics = true + enable_pod_metrics = true + enable_statefulset_metrics = true + enable_storage_metrics = true + enable_api_server_metrics = true + enable_controller_manager_metrics = true + enable_scheduler_metrics = true + } +} + +module "db" { + source = "../../../modules/cloudsql-instance" + project_id = module.project.project_id + databases = ["bindplane"] + network_config = { + connectivity = { + psc_allowed_consumer_projects = [module.project.project_id] + } + } + prefix = var.prefix + name = "bindplane" + region = var.region + availability_type = var.postgresql_config.availability_type + database_version = var.postgresql_config.database_version + tier = var.postgresql_config.tier + + users = { + bindplane = { + password = null + type = "BUILT_IN" + } + } + + gcp_deletion_protection = false + terraform_deletion_protection = false +} + +module "addresses" { + source = "../../../modules/net-address" + project_id = module.project.project_id + internal_addresses = { + ingress = { + purpose = "SHARED_LOADBALANCER_VIP" + region = var.region + subnetwork = var.network_config.subnet_self_link + } + } + psc_addresses = { + postgresql = { + address = "" + region = var.region + subnet_self_link = var.network_config.subnet_self_link + service_attachment = { + psc_service_attachment_link = module.db.psc_service_attachment_link + global_access = true + } + } + } +} + +module "dns" { + source = "../../../modules/dns" + count = var.dns_config.bootstrap_private_zone ? 1 : 0 + project_id = module.project.project_id + name = "bindplane" + zone_config = { + domain = "${var.dns_config.domain}." + private = { + client_networks = [var.network_config.network_self_link] + } + } + recordsets = { + "A ${var.dns_config.hostname}" = { ttl = 600, records = [module.addresses.internal_addresses["ingress"].address] } + } +} + +module "pubsub" { + source = "../../../modules/pubsub" + project_id = module.project.project_id + name = "bindplane" +} + +module "bindplane-sa" { + source = "../../../modules/iam-service-account" + project_id = module.project.project_id + name = "bindplane" + iam = { + "roles/iam.workloadIdentityUser" = ["serviceAccount:${module.project.project_id}.svc.id.goog[bindplane/bindplane]"] + } + iam_project_roles = { + "${module.project.project_id}" = [ + "roles/pubsub.editor" + ] + } +} + +module "bindplane-deployment" { + source = "./bindplane-deployment" + depends_on = [module.bindplane-cluster] + bindplane_secrets = var.bindplane_secrets + bindplane_tls = { + cer = coalesce(var.bindplane_config.tls_certificate_cer, try(tls_locally_signed_cert.server_singed_cert.0.cert_pem, null)) + key = coalesce(var.bindplane_config.tls_certificate_key, try(tls_private_key.server_key.0.private_key_pem, null)) + } +} + +resource "helm_release" "bindplane" { + name = "bindplane" + repository = "https://observiq.github.io/bindplane-op-helm" + chart = "bindplane" + namespace = "bindplane" + create_namespace = false + values = [templatefile("${path.module}/config/values.yaml.tpl", { + postgresql_ip = module.addresses.psc_addresses["postgresql"].address + postgresql_username = "bindplane" + postgresql_password = module.db.user_passwords["bindplane"] + gcp_project_id = module.project.project_id + hostname = "${var.dns_config.hostname}.${var.dns_config.domain}" + address = "ingress" + })] + + depends_on = [ + module.bindplane-deployment, + module.addresses + ] +} diff --git a/blueprints/secops/bindplane-gke/outputs.tf b/blueprints/secops/bindplane-gke/outputs.tf new file mode 100644 index 000000000..a8ee465c3 --- /dev/null +++ b/blueprints/secops/bindplane-gke/outputs.tf @@ -0,0 +1,40 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +output "bindplane_hostname" { + description = "BindPlane OP Management console hostname." + value = "https://${var.dns_config.hostname}.${var.dns_config.domain}" +} + +output "ca_cert" { + description = "TLS CA certificate." + value = try(tls_self_signed_cert.ca_cert.0.cert_pem, null) +} + +output "cluster_ca_certificate" { + description = "GKE CA Certificate." + value = module.bindplane-cluster.ca_certificate +} + +output "fleet_host" { + description = "GKE Fleet host." + value = local.fleet_host +} + +output "lb_ip_address" { + description = "Ingress LB address." + value = module.addresses.internal_addresses["ingress"].address +} diff --git a/blueprints/secops/bindplane-gke/ssl.tf b/blueprints/secops/bindplane-gke/ssl.tf new file mode 100644 index 000000000..7fd460f3e --- /dev/null +++ b/blueprints/secops/bindplane-gke/ssl.tf @@ -0,0 +1,107 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +locals { + bootstrap_self_signed_cert = var.bindplane_config.tls_certificate_cer == null || var.bindplane_config.tls_certificate_key == null + cert_subjects = [ + { + country = "IT" + province = "Lombardy" + locality = "Milan" + organization = "Example" + organizational_unit = "Example" + } + ] +} + +####################################################################### +# CA PRIVATE KEY # +####################################################################### + +resource "tls_private_key" "ca_private_key" { + count = local.bootstrap_self_signed_cert ? 1 : 0 + algorithm = "RSA" +} + +####################################################################### +# CA CERT # +####################################################################### + +resource "tls_self_signed_cert" "ca_cert" { + count = local.bootstrap_self_signed_cert ? 1 : 0 + private_key_pem = tls_private_key.ca_private_key.0.private_key_pem + is_ca_certificate = true + dynamic "subject" { + for_each = toset(local.cert_subjects) + content { + country = subject.value.country + province = subject.value.province + locality = subject.value.locality + common_name = "Bindplane" + organization = subject.value.organization + organizational_unit = subject.value.organization + } + } + validity_period_hours = 87600 // 3650 days or 10 years + allowed_uses = [ + "digital_signature", + "cert_signing", + "crl_signing", + ] +} + +####################################################################### +# SERVER CERT SIGNED BY CA # +####################################################################### + +resource "tls_private_key" "server_key" { + count = local.bootstrap_self_signed_cert ? 1 : 0 + algorithm = "RSA" +} + +resource "tls_cert_request" "server_csr" { + count = local.bootstrap_self_signed_cert ? 1 : 0 + private_key_pem = tls_private_key.server_key.0.private_key_pem + dns_names = ["${var.dns_config.hostname}.${var.dns_config.domain}"] + + dynamic "subject" { + for_each = toset(local.cert_subjects) + content { + country = subject.value.country + province = subject.value.province + locality = subject.value.locality + common_name = "Gitlab" + organization = subject.value.organization + organizational_unit = subject.value.organization + } + } +} + +resource "tls_locally_signed_cert" "server_singed_cert" { + count = local.bootstrap_self_signed_cert ? 1 : 0 + cert_request_pem = tls_cert_request.server_csr.0.cert_request_pem + ca_private_key_pem = tls_private_key.ca_private_key.0.private_key_pem + ca_cert_pem = tls_self_signed_cert.ca_cert.0.cert_pem + + validity_period_hours = 87600 // 3650 days or 10 years + + allowed_uses = [ + "digital_signature", + "key_encipherment", + "server_auth", + "client_auth", + ] +} diff --git a/blueprints/secops/bindplane-gke/variables.tf b/blueprints/secops/bindplane-gke/variables.tf new file mode 100644 index 000000000..973c5db18 --- /dev/null +++ b/blueprints/secops/bindplane-gke/variables.tf @@ -0,0 +1,106 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +variable "bindplane_config" { + description = "Bindplane config." + type = object({ + tls_certificate_cer = optional(string, null) + tls_certificate_key = optional(string, null) + }) + default = {} +} + +variable "bindplane_secrets" { + description = "Bindplane secrets." + type = object({ + license = string + user = optional(string, "admin") + password = optional(string, null) + sessions_secret = string + }) +} + +variable "cluster_config" { + description = "GKE cluster configuration." + type = object({ + cluster_name = optional(string, "bindplane-op") + master_authorized_ranges = optional(map(string), { + rfc-1918-10-8 = "10.0.0.0/8" + }) + }) + default = {} +} + +variable "dns_config" { + description = "DNS config." + type = object({ + bootstrap_private_zone = optional(bool, false) + domain = optional(string, "example.com") + hostname = optional(string, "bindplane") + }) + default = {} +} + +variable "network_config" { + description = "Shared VPC network configurations to use for GKE cluster." + type = object({ + host_project = optional(string) + network_self_link = string + subnet_self_link = string + ip_range_gke_master = string + secondary_pod_range_name = optional(string, "pods") + secondary_services_range_name = optional(string, "services") + }) +} + +variable "postgresql_config" { + description = "Cloud SQL postgresql config." + type = object({ + availability_type = optional(string, "REGIONAL") + database_version = optional(string, "POSTGRES_13") + tier = optional(string, "db-g1-small") + }) + default = {} +} + +variable "prefix" { + description = "Prefix used for resource names." + type = string + nullable = false + validation { + condition = var.prefix != "" + error_message = "Prefix cannot be empty." + } +} + +variable "project_create" { + description = "Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format." + type = object({ + billing_account_id = string + parent = string + }) + default = null +} + +variable "project_id" { + description = "Project id, references existing project if `project_create` is null." + type = string +} + +variable "region" { + description = "GCP region." + type = string +} diff --git a/tools/lockfile/main.tf b/tools/lockfile/main.tf index 9c8a3e704..6670ff63c 100644 --- a/tools/lockfile/main.tf +++ b/tools/lockfile/main.tf @@ -23,3 +23,4 @@ resource "random_pet" "default" {} resource "time_static" "default" {} resource "tls_private_key" "default" {} resource "vsphere_role" "default" {} +resource "kubernetes_secret" "default" {}