From d1770496e1532b3d0e388aacbe7f3348afab8882 Mon Sep 17 00:00:00 2001 From: robo-cap Date: Thu, 21 Mar 2024 18:04:14 +0200 Subject: [PATCH] added service account extension --- ...ars-extensions-service-account.auto.tfvars | 27 ++++ module-extensions.tf | 6 +- modules/extensions/service_account.tf | 126 ++++++++++++++++++ modules/extensions/variables.tf | 4 + variables-extensions.tf | 20 +++ 5 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 examples/extensions/vars-extensions-service-account.auto.tfvars create mode 100644 modules/extensions/service_account.tf diff --git a/examples/extensions/vars-extensions-service-account.auto.tfvars b/examples/extensions/vars-extensions-service-account.auto.tfvars new file mode 100644 index 00000000..c55ce5a9 --- /dev/null +++ b/examples/extensions/vars-extensions-service-account.auto.tfvars @@ -0,0 +1,27 @@ +# Copyright (c) 2024 Oracle Corporation and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl + +create_service_account = true +service_accounts = { + # Example to create a cluster role binding using a cluster role. + example_cluster_role_binding = { + sa_name = "sa1" + sa_namespace = "kube-system" + sa_cluster_role = "cluster-admin" + sa_cluster_role_binding = "sa1-crb" + } + # Example to create a role binding using a cluster role. + example_role_binding = { + sa_name = "sa2" + sa_namespace = "default" + sa_cluster_role = "cluster-admin" + sa_role_binding = "sa1-rb" + } + # Example to create a role binding using a role, the role needs to exist within the namespace. + example_role_binding = { + sa_name = "sa3" + sa_namespace = "kube-system" + sa_role = "system:controller:token-cleaner" + sa_role_binding = "sa3-rb" + } +} \ No newline at end of file diff --git a/module-extensions.tf b/module-extensions.tf index 884e50c9..194e4a40 100644 --- a/module-extensions.tf +++ b/module-extensions.tf @@ -3,7 +3,7 @@ module "extensions" { source = "./modules/extensions" - count = alltrue([var.create_cluster,local.operator_enabled]) ? 1 : 0 + count = alltrue([var.create_cluster, local.operator_enabled]) ? 1 : 0 region = var.region state_id = local.state_id @@ -106,4 +106,8 @@ module "extensions" { mpi_operator_namespace = var.mpi_operator_namespace mpi_operator_deployment_url = var.mpi_operator_deployment_url mpi_operator_version = var.mpi_operator_version + + # Service Account + create_service_account = var.create_service_account + service_accounts = var.service_accounts } diff --git a/modules/extensions/service_account.tf b/modules/extensions/service_account.tf new file mode 100644 index 00000000..44363f07 --- /dev/null +++ b/modules/extensions/service_account.tf @@ -0,0 +1,126 @@ +# Copyright (c) 2024 Oracle Corporation and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl + +locals { + sa_with_cluster_role_bindings = { + for k, v in var.service_accounts: k => v + if lookup(v, "sa_cluster_role_binding", null) != null + } + sa_with_role_bindings = { + for k, v in var.service_accounts: k => v + if lookup(v, "sa_role_binding", null) != null + } +} + +resource "null_resource" "service_account_crb" { + for_each = var.create_service_account ? local.sa_with_cluster_role_bindings : {} + + triggers = { + service_account_name = each.value.sa_name + service_account_namespace = each.value.sa_namespace + service_account_cluster_role = each.value.sa_cluster_role + service_account_cluster_role_binding = each.value.sa_cluster_role_binding + + # Parameters ignored as triggers in the life_cycle block. Required to establish connections. + bastion_host = var.bastion_host + bastion_user = var.bastion_user + ssh_private_key = var.ssh_private_key + operator_host = var.operator_host + operator_user = var.operator_user + } + + connection { + bastion_host = self.triggers.bastion_host + bastion_user = self.triggers.bastion_user + bastion_private_key = self.triggers.ssh_private_key + host = self.triggers.operator_host + user = self.triggers.operator_user + private_key = self.triggers.ssh_private_key + timeout = "40m" + type = "ssh" + } + + provisioner "remote-exec" { + inline = [ + "kubectl get ns ${self.triggers.service_account_namespace} || kubectl create ns ${self.triggers.service_account_namespace}", + "kubectl create sa -n ${self.triggers.service_account_namespace} ${self.triggers.service_account_name}", + "kubectl create clusterrolebinding ${self.triggers.service_account_cluster_role_binding} --clusterrole=${self.triggers.service_account_cluster_role} --serviceaccount=${self.triggers.service_account_namespace}:${self.triggers.service_account_name}" + ] + } + + provisioner "remote-exec" { + when = destroy + inline = [ + "kubectl delete clusterrolebinding ${self.triggers.service_account_cluster_role_binding}", + "kubectl delete sa -n ${self.triggers.service_account_namespace} ${self.triggers.service_account_name}" + ] + } + + lifecycle { + ignore_changes = [ + triggers["bastion_host"], + triggers["bastion_user"], + triggers["ssh_private_key"], + triggers["operator_host"], + triggers["operator_user"] + ] + } +} + +resource "null_resource" "service_account_rb" { + for_each = var.create_service_account ? local.sa_with_role_bindings : {} + + triggers = { + service_account_name = each.value.sa_name + service_account_namespace = each.value.sa_namespace + service_account_cluster_role = each.value.sa_cluster_role + service_account_role = lookup(each.value, "sa_role", "") + service_account_role_binding = each.value.sa_role_binding + + # Parameters ignored as triggers in the life_cycle block. Required to establish connections. + bastion_host = var.bastion_host + bastion_user = var.bastion_user + ssh_private_key = var.ssh_private_key + operator_host = var.operator_host + operator_user = var.operator_user + } + + connection { + bastion_host = self.triggers.bastion_host + bastion_user = self.triggers.bastion_user + bastion_private_key = self.triggers.ssh_private_key + host = self.triggers.operator_host + user = self.triggers.operator_user + private_key = self.triggers.ssh_private_key + timeout = "40m" + type = "ssh" + } + + provisioner "remote-exec" { + inline = [ + "kubectl get ns ${self.triggers.service_account_namespace} || kubectl create ns ${self.triggers.service_account_namespace}", + "kubectl create sa -n ${self.triggers.service_account_namespace} ${self.triggers.service_account_name}", + self.triggers.service_account_role != "" ? + "kubectl create rolebinding -n ${self.triggers.service_account_namespace} ${self.triggers.service_account_role_binding} --role=${self.triggers.service_account_role} --serviceaccount=${self.triggers.service_account_namespace}:${self.triggers.service_account_name}" : + "kubectl create rolebinding -n ${self.triggers.service_account_namespace} ${self.triggers.service_account_role_binding} --clusterrole=${self.triggers.service_account_cluster_role} --serviceaccount=${self.triggers.service_account_namespace}:${self.triggers.service_account_name}" + ] + } + + provisioner "remote-exec" { + when = destroy + inline = [ + "kubectl delete rolebinding -n ${self.triggers.service_account_namespace} ${self.triggers.service_account_role_binding}", + "kubectl delete sa -n ${self.triggers.service_account_namespace} ${self.triggers.service_account_name}" + ] + } + + lifecycle { + ignore_changes = [ + triggers["bastion_host"], + triggers["bastion_user"], + triggers["ssh_private_key"], + triggers["operator_host"], + triggers["operator_user"] + ] + } +} \ No newline at end of file diff --git a/modules/extensions/variables.tf b/modules/extensions/variables.tf index be1a57fa..a89aa0b5 100644 --- a/modules/extensions/variables.tf +++ b/modules/extensions/variables.tf @@ -101,3 +101,7 @@ variable "gatekeeper_namespace" { type = string } variable "gatekeeper_helm_version" { type = string } variable "gatekeeper_helm_values" { type = map(string) } variable "gatekeeper_helm_values_files" { type = list(string) } + +# Service Account +variable "create_service_account" { type = bool } +variable "service_accounts" { type = map(any) } \ No newline at end of file diff --git a/variables-extensions.tf b/variables-extensions.tf index b5488885..a7706d0f 100644 --- a/variables-extensions.tf +++ b/variables-extensions.tf @@ -367,3 +367,23 @@ variable "gatekeeper_helm_values_files" { type = list(string) } +# Service Account + +variable "create_service_account" { + default = false + description = "Wether to create a service account or not." + type = bool +} + +variable "service_accounts" { + default = { + kubeconfigsa = { + sa_name = "kubeconfigsa" + sa_namespace = "kube-system" + sa_cluster_role = "cluster-admin" + sa_cluster_role_binding = "kubeconfigsa-crb" + } + } + description = "Map of service accounts and associated parameters." + type = map(any) +} \ No newline at end of file