Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Azure AAD/EntraID access settings #2887

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/_nebari/stages/infrastructure/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,27 @@ class AzureNodeGroupInputVars(schema.Base):
max_nodes: int


class AzureRBAC(schema.Base):
"""
Represents the configuration for Azure Active Directory Role-Based Access Control
(RBAC) integration in a Kubernetes cluster.

Attributes:
enabled (bool): Indicates whether Azure AD-based Role-Based Access Control is
enabled.
managed (bool): Specifies if the Azure AD integration is managed by Azure.
When set to True, Azure creates and manages the Service Principal used for
integration.
admin_group_object_ids (List[str]): A list of Object IDs of Azure AD groups assigned
administrative roles on the cluster. This property is only applicable when
`managed` is set to True.
"""

enabled: bool
managed_identity: bool
admin_group_object_ids: List[str]


class AzureInputVars(schema.Base):
name: str
environment: str
Expand All @@ -105,6 +126,7 @@ class AzureInputVars(schema.Base):
max_pods: Optional[int] = None
network_profile: Optional[Dict[str, str]] = None
workload_identity_enabled: bool = False
azure_rbac: Optional[AzureRBAC] = None


class AWSAmiTypes(str, enum.Enum):
Expand Down Expand Up @@ -370,6 +392,7 @@ class AzureProvider(schema.Base):
network_profile: Optional[Dict[str, str]] = None
max_pods: Optional[int] = None
workload_identity_enabled: bool = False
azure_rbac: Optional[AzureRBAC] = None

@model_validator(mode="before")
@classmethod
Expand Down Expand Up @@ -809,6 +832,7 @@ def input_vars(self, stage_outputs: Dict[str, Dict[str, Any]]):
network_profile=self.config.azure.network_profile,
max_pods=self.config.azure.max_pods,
workload_identity_enabled=self.config.azure.workload_identity_enabled,
azure_rbac=self.config.azure.azure_rbac,
).model_dump()
elif self.config.provider == schema.ProviderEnum.aws:
return AWSInputVars(
Expand Down
1 change: 1 addition & 0 deletions src/_nebari/stages/infrastructure/template/azure/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ module "kubernetes" {
vnet_subnet_id = var.vnet_subnet_id
private_cluster_enabled = var.private_cluster_enabled
workload_identity_enabled = var.workload_identity_enabled
azure_rbac = var.azure_rbac
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
output "credentials" {
description = "Credentials required for connecting to Kubernetes cluster"
sensitive = true
value = {
endpoint = var.azure_rbac_enabled ? var.kube_admin_config.host : var.kube_config.host
username = var.azure_rbac_enabled ? var.kube_admin_config.username : var.kube_config.username
password = var.azure_rbac_enabled ? var.kube_admin_config.password : var.kube_config.password
client_certificate = var.azure_rbac_enabled ? base64decode(var.kube_admin_config.client_certificate) : base64decode(var.kube_config.client_certificate)
client_key = var.azure_rbac_enabled ? base64decode(var.kube_admin_config.client_key) : base64decode(var.kube_config.client_key)
cluster_ca_certificate = var.azure_rbac_enabled ? base64decode(var.kube_admin_config.cluster_ca_certificate) : base64decode(var.kube_config.cluster_ca_certificate)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
variable "azure_rbac_enabled" {
description = "Flag to enable Azure RBAC"
type = bool
}

variable "kube_admin_config" {
description = "Kube admin config for RBAC"
type = any
sensitive = true
}

variable "kube_config" {
description = "Kube config for standard access"
type = any
sensitive = true
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
data "azurerm_client_config" "current" {
count = var.azure_rbac.enabled ? 1 : 0
}

# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster
resource "azurerm_kubernetes_cluster" "main" {
name = var.name
Expand Down Expand Up @@ -61,6 +65,15 @@ resource "azurerm_kubernetes_cluster" "main" {
]
}

dynamic "azure_active_directory_role_based_access_control" {
for_each = var.azure_rbac.enabled ? [var.azure_rbac] : []
content {
azure_rbac_enabled = var.azure_rbac.enabled
admin_group_object_ids = var.azure_rbac.admin_group_object_ids
tenant_id = data.azurerm_client_config.current[0].tenant_id
managed = var.azure_rbac.managed_identity
}
}
}

# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster_node_pool
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
module "k8s_credentials" {
source = "../credentials"
azure_rbac_enabled = var.azure_rbac.enabled
kube_admin_config = azurerm_kubernetes_cluster.main.kube_admin_config[0]
kube_config = azurerm_kubernetes_cluster.main.kube_config[0]
}

output "credentials" {
description = "Credentials required for connecting to kubernetes cluster"
description = "Credentials required for connecting to Kubernetes cluster"
sensitive = true
value = {
# see bottom of https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster
endpoint = azurerm_kubernetes_cluster.main.kube_config.0.host
username = azurerm_kubernetes_cluster.main.kube_config.0.username
password = azurerm_kubernetes_cluster.main.kube_config.0.password
client_certificate = base64decode(azurerm_kubernetes_cluster.main.kube_config.0.client_certificate)
client_key = base64decode(azurerm_kubernetes_cluster.main.kube_config.0.client_key)
cluster_ca_certificate = base64decode(azurerm_kubernetes_cluster.main.kube_config.0.cluster_ca_certificate)
}
value = module.k8s_credentials.credentials
}

output "kubeconfig" {
description = "Kubernetes connection kubeconfig"
sensitive = true
value = azurerm_kubernetes_cluster.main.kube_config_raw
value = var.azure_rbac.enabled ? azurerm_kubernetes_cluster.main.kube_admin_config_raw : azurerm_kubernetes_cluster.main.kube_config_raw
}

output "cluster_oidc_issuer_url" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,18 @@ variable "workload_identity_enabled" {
type = bool
default = false
}

variable "azure_rbac" {
description = "Azure Active Directory Role-Based Access Control (RBAC) integration in a Kubernetes cluster"
type = object({
enabled : bool
managed_identity : bool
admin_group_object_ids : list(string)
})
default = {
enabled : false
managed_identity : false
admin_group_object_ids : []
}
nullable = false
}
14 changes: 14 additions & 0 deletions src/_nebari/stages/infrastructure/template/azure/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,17 @@ variable "workload_identity_enabled" {
type = bool
default = false
}

variable "azure_rbac" {
description = "Azure Active Directory Role-Based Access Control (RBAC) integration in a Kubernetes cluster"
type = object({
enabled : bool
managed_identity : bool
admin_group_object_ids : list(string)
})
default = {
enabled : false
managed_identity : false
admin_group_object_ids : []
}
}
Loading