blueprints/secops/secops-gke-forwarder/secops-forwarder-deployment/main.tf (269 lines of code) (raw):
/**
* 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 {
_chronicle_forwarder_default_lb_ports = [
"2001", "2011", "2021", "2031", "2041", "2051", "2061", "2071"
]
chronicle_forwarder_config = {
for key, value in var.tenants : key =>
coalesce(value.forwarder_config.config_file_content, try(templatefile("${path.module}/data/default-config.yaml.tpl", {
chronicle_url = "${value.chronicle_region}-malachiteingestion-pa.googleapis.com:443",
customer_id = value.forwarder_config.customer_id
collector_id = value.forwarder_config.collector_id
secret_key = value.forwarder_config.secret_key
tls_required = value.forwarder_config.tls_config.required
}), null))
}
deployment_names = {
for key, value in var.tenants : key => "cfps-${value.tenant_id}"
}
tenants_exposing_service_attachments = {
for key, value in var.tenants : key => value if value.network_config.expose_service_attachment
}
tenants_exposing_udp_service_attachments = {
for key, value in var.tenants : key => value if value.network_config.expose_service_attachment && value.forwarder_config.tls_config == null
}
tenants_chronicle_forwarder_lb_ports = {
for k, v in var.tenants : k => coalesce(v.network_config.load_balancer_ports, local._chronicle_forwarder_default_lb_ports)
}
tenants_secret_tls = {
for k, v in var.tenants : k => {
cer = try(tls_locally_signed_cert.forwarder_server_singed_cert[k].cert_pem, v.forwarder_config.tls_config.cert_pub)
key = try(tls_private_key.forwarder_server_key[k].private_key_pem, v.forwarder_config.tls_config.cert_key)
} if v.forwarder_config.tls_config.required
}
}
resource "kubernetes_namespace" "namespace" {
for_each = var.tenants
metadata {
name = each.value.namespace
}
}
resource "kubernetes_service" "service_tcp" {
for_each = var.tenants
metadata {
name = "cfps-${each.value.tenant_id}-tcp"
namespace = kubernetes_namespace.namespace[each.key].metadata[0].name
annotations = {
"networking.gke.io/load-balancer-type" = "Internal"
}
}
spec {
selector = {
app = local.deployment_names[each.key]
}
type = "LoadBalancer"
port {
name = "hc"
protocol = "TCP"
port = 8080
target_port = 8080
}
dynamic "port" {
for_each = local.tenants_chronicle_forwarder_lb_ports[each.key]
content {
name = "tcp-${port.value}"
protocol = "TCP"
port = port.value
target_port = port.value
}
}
}
timeouts {
create = "5m"
}
}
resource "kubectl_manifest" "service_attachment_tcp" {
for_each = local.tenants_exposing_service_attachments
yaml_body = templatefile("${path.module}/manifests/service-attachment.yaml", {
tenant = each.value.tenant_id
namespace = kubernetes_namespace.namespace[each.key].metadata[0].name
service_name = kubernetes_service.service_tcp[each.key].metadata[0].name
})
timeouts {
create = "5m"
}
}
resource "kubernetes_service" "service_udp" {
for_each = { for k, v in var.tenants : k => v if v.forwarder_config.tls_config != null }
metadata {
name = "cfps-${each.value.tenant_id}-udp"
namespace = kubernetes_namespace.namespace[each.key].metadata[0].name
annotations = {
"networking.gke.io/load-balancer-type" = "Internal"
}
}
spec {
selector = {
app = local.deployment_names[each.key]
}
type = "LoadBalancer"
dynamic "port" {
for_each = local.tenants_chronicle_forwarder_lb_ports[each.key]
content {
name = "udp-${port.value}"
protocol = "UDP"
port = port.value
target_port = port.value
}
}
}
}
resource "kubectl_manifest" "service_attachment_udp" {
for_each = local.tenants_exposing_udp_service_attachments
yaml_body = templatefile("${path.module}/manifests/service-attachment.yaml", {
tenant = each.value.tenant_id
namespace = kubernetes_namespace.namespace[each.key].metadata[0].name
service_name = kubernetes_service.service_udp[each.key].metadata[0].name
})
timeouts {
create = "5m"
}
}
resource "kubernetes_deployment" "cfps" {
for_each = var.tenants
metadata {
name = local.deployment_names[each.key]
namespace = kubernetes_namespace.namespace[each.key].metadata[0].name
labels = {
app = local.deployment_names[each.key]
}
}
spec {
replicas = 2 # default number of pods
selector {
match_labels = {
app = local.deployment_names[each.key]
}
}
template {
metadata {
labels = {
app = local.deployment_names[each.key]
}
}
spec {
container {
name = "cfps"
image = "gcr.io/chronicle-container/${var.tenants[each.key].chronicle_forwarder_image}"
image_pull_policy = "IfNotPresent"
resources {
requests = {
cpu = "2" # 2 CPUs requested
memory = "2Gi" # 2 GB of RAM requested
}
limits = {
cpu = "4" # 4 CPUs limit
memory = "6Gi" # 4 GB of RAM limit
}
}
volume_mount {
mount_path = "/opt/chronicle/external/"
name = kubernetes_secret.secret_config[each.key].metadata[0].name
read_only = true
}
dynamic "volume_mount" {
for_each = try(kubernetes_secret.tls[each.key], null) != null ? [""] : []
content {
mount_path = "/opt/chronicle/external/certs"
name = kubernetes_secret.tls[each.key].metadata[0].name
read_only = true
}
}
liveness_probe {
http_get {
path = "/meta/available"
port = 8080
}
failure_threshold = 3
period_seconds = 30
}
readiness_probe {
http_get {
path = "/meta/ready"
port = 8080
}
failure_threshold = 1
period_seconds = 30
}
}
volume {
name = kubernetes_secret.secret_config[each.key].metadata[0].name
secret {
secret_name = kubernetes_secret.secret_config[each.key].metadata[0].name
}
}
dynamic "volume" {
for_each = try(kubernetes_secret.tls[each.key], null) != null ? [""] : []
content {
name = kubernetes_secret.tls[each.key].metadata[0].name
secret {
secret_name = kubernetes_secret.tls[each.key].metadata[0].name
}
}
}
}
}
}
}
resource "kubernetes_horizontal_pod_autoscaler_v2" "cfps" {
for_each = var.tenants
metadata {
name = "${local.deployment_names[each.key]}-hpa"
namespace = kubernetes_namespace.namespace[each.key].metadata[0].name
}
spec {
scale_target_ref {
kind = "Deployment"
name = kubernetes_deployment.cfps[each.key].metadata[0].name
}
min_replicas = 2 # Minimum number of pods
max_replicas = 5 # Maximum allowed replicas
metric {
type = "Resource"
resource {
name = "cpu"
target {
type = "Utilization"
average_utilization = "80"
}
}
}
}
}
resource "kubernetes_secret" "secret_config" {
for_each = var.tenants
metadata {
name = "cfps-secret-config-${each.key}"
namespace = kubernetes_namespace.namespace[each.key].metadata[0].name
}
data = {
"config.conf" = local.chronicle_forwarder_config[each.key]
}
type = "Opaque"
}
resource "kubernetes_secret" "tls" {
for_each = local.tenants_secret_tls
metadata {
name = "cfps-secret-tls-${each.key}"
namespace = kubernetes_namespace.namespace[each.key].metadata[0].name
}
data = {
"tls.crt" = each.value.cer
"tls.key" = each.value.key
}
type = "kubernetes.io/tls"
}