diff --git a/nullplatform/cloud/azure/cloud/main.tf b/nullplatform/cloud/azure/cloud/main.tf index bfb0682c..d0d52b0a 100644 --- a/nullplatform/cloud/azure/cloud/main.tf +++ b/nullplatform/cloud/azure/cloud/main.tf @@ -6,7 +6,14 @@ resource "nullplatform_provider_config" "azure" { dimensions = var.dimensions attributes = jsonencode({ - authentication = {}, + authentication = { + for k, v in { + client_id = var.client_id + client_secret = var.client_secret + subscription_id = var.subscription_id + tenant_id = var.tenant_id + } : k => v if v != null + }, networking = { application_domain = var.application_domain, domain_name = var.domain_name, @@ -17,6 +24,14 @@ resource "nullplatform_provider_config" "azure" { } }) lifecycle { + precondition { + condition = ( + (var.client_id == null) == (var.client_secret == null) && + (var.client_id == null) == (var.subscription_id == null) && + (var.client_id == null) == (var.tenant_id == null) + ) + error_message = "Authentication credentials must all be set or all be null (client_id, client_secret, subscription_id, tenant_id)." + } ignore_changes = [attributes] } } diff --git a/nullplatform/cloud/azure/cloud/tests/azure_cloud.tftest.hcl b/nullplatform/cloud/azure/cloud/tests/azure_cloud.tftest.hcl index 1496e78c..c482961e 100644 --- a/nullplatform/cloud/azure/cloud/tests/azure_cloud.tftest.hcl +++ b/nullplatform/cloud/azure/cloud/tests/azure_cloud.tftest.hcl @@ -34,6 +34,54 @@ run "attributes_contain_resource_groups" { } } +run "with_authentication_credentials" { + command = plan + + variables { + client_id = "11111111-0000-0000-0000-000000000001" + client_secret = "dummy-secret-for-testing-purposes-only!" + subscription_id = "22222222-0000-0000-0000-000000000002" + tenant_id = "33333333-0000-0000-0000-000000000003" + } + + assert { + condition = strcontains(nullplatform_provider_config.azure.attributes, "11111111-0000-0000-0000-000000000001") + error_message = "Attributes should contain the client_id when provided" + } + + assert { + condition = strcontains(nullplatform_provider_config.azure.attributes, "22222222-0000-0000-0000-000000000002") + error_message = "Attributes should contain the subscription_id when provided" + } + + assert { + condition = strcontains(nullplatform_provider_config.azure.attributes, "33333333-0000-0000-0000-000000000003") + error_message = "Attributes should contain the tenant_id when provided" + } +} + +run "without_authentication_credentials" { + command = plan + + assert { + condition = strcontains(nullplatform_provider_config.azure.attributes, "\"authentication\":{}") || strcontains(nullplatform_provider_config.azure.attributes, "\"authentication\": {}") + error_message = "Authentication block should be empty when no credentials provided (inherits from parent)" + } +} + +run "partial_authentication_fails" { + command = plan + + variables { + client_id = "11111111-0000-0000-0000-000000000001" + # client_secret, subscription_id, tenant_id omitted intentionally + } + + expect_failures = [ + nullplatform_provider_config.azure, + ] +} + run "with_domain_name" { command = plan diff --git a/nullplatform/cloud/azure/cloud/variables.tf b/nullplatform/cloud/azure/cloud/variables.tf index a719859c..c1fcc476 100644 --- a/nullplatform/cloud/azure/cloud/variables.tf +++ b/nullplatform/cloud/azure/cloud/variables.tf @@ -3,6 +3,31 @@ variable "nrn" { description = "The NRN of your nullplatform account" } +variable "client_id" { + type = string + description = "Azure Service Principal client ID. If omitted, inherits from a parent cloud provider." + default = null +} + +variable "client_secret" { + type = string + description = "Azure Service Principal client secret. If omitted, inherits from a parent cloud provider." + sensitive = true + default = null +} + +variable "subscription_id" { + type = string + description = "Azure subscription ID. If omitted, inherits from a parent cloud provider." + default = null +} + +variable "tenant_id" { + type = string + description = "Azure Active Directory tenant ID. If omitted, inherits from a parent cloud provider." + default = null +} + variable "domain_name" { description = "The domain name to be used" type = string