This Terraform configuration deploys Crossplane on Azure Kubernetes Service (AKS) with Azure Service Principal authentication.
The implementation consists of:
-
Azure Infrastructure (
crossplane_infrastructure.tf):- Azure AD App Registration:
azure-operators-sp - Service Principal: Created from app registration with Contributor role
- Subscription-level Contributor role assignment
- Azure AD App Registration:
-
Kubernetes Resources (
crossplane_argocd.tf):- ArgoCD Application for Crossplane installation
- Provider installations (provider-family-azure, provider-azure-cache)
- ClusterProviderConfig for Azure authentication using Secret credentials
- Kubernetes Secret with JSON credentials
-
App Registration:
azure-operators-sp- Azure AD application used as the identity for Crossplane and ASO
-
Service Principal: Created from app registration with Contributor role
- Permissions: Contributor role at subscription level
All resources are deployed in the resources-system namespace:
-
ArgoCD Application:
crossplane- Helm chart from Crossplane stable repository
- Chart version
2.1.3(hardcoded in ArgoCD manifest)
-
Providers:
upbound-provider-family-azure(version fromvar.crossplane_provider_family_azure_version)provider-redis-azure(version fromvar.crossplane_provider_azure_cache_version)
-
ClusterProviderConfig:
default- Uses Secret source for authentication
- References
azure-crossplane-credentialssecret
-
Secret:
azure-crossplane-credentials- Stores JSON credentials:
clientId,clientSecret,subscriptionId,tenantId
- Stores JSON credentials:
-
ASO controller settings secret
- Reuses the same Service Principal credentials for Azure Service Operator
| Variable | Description | Default |
|---|---|---|
crossplane_version |
Version of Crossplane chart (hardcoded at 2.1.3 in ArgoCD manifest) |
2.1.3 |
crossplane_provider_family_azure_version |
Version of provider-family-azure | v2.3.0 |
crossplane_provider_azure_cache_version |
Version of provider-azure-cache | v2.3.0 |
| Output | Description |
|---|---|
crossplane_identity_client_id |
The Client ID of the Crossplane app registration |
crossplane_identity_principal_id |
The Principal ID of the Crossplane service principal |
crossplane_subscription_id |
The Azure Subscription ID used by Crossplane |
crossplane_tenant_id |
The Azure Tenant ID used by Crossplane |
-
AKS cluster configured
-
ArgoCD installed and configured in
devops-systemnamespace -
Environment variables:
ARM_SUBSCRIPTION_ID: Azure subscription ID
The Terraform configuration ensures proper dependency ordering:
- Azure infrastructure (App Registration, Service Principal, Role Assignment)
- AKS cluster and namespaces
- ArgoCD installation and configuration
- Crossplane ArgoCD Application (deployed to
control-plane-systemnamespace) - Provider installations
- ClusterProviderConfig
- Credentials secret
The implementation uses an Azure AD Service Principal with client secret:
- App Registration:
azure-operators-spcreated in Azure AD - Service Principal: Gets Contributor role at subscription level
- Client Secret: Stored as Kubernetes Secret
azure-crossplane-credentials - ClusterProviderConfig: References the secret for authentication
- Terraform creates an Azure AD App Registration and Service Principal
- A client secret is generated and stored as a Kubernetes Secret
- The secret contains JSON with
clientId,clientSecret,subscriptionId, andtenantId - The
ClusterProviderConfigreferences this secret usingcredentials.source: Secret - Providers authenticate using the client secret credentials
- Azure Service Operator (ASO v2.17.0) reuses the same Service Principal
kubectl get pods -n resources-system
kubectl get providers -n resources-system# Check the credentials secret exists
kubectl get secret azure-crossplane-credentials -n resources-system
# Verify ClusterProviderConfig is healthy
kubectl get clusterproviderconfig default
kubectl describe clusterproviderconfig defaultkubectl apply -f - <<EOF
apiVersion: cache.azure.m.upbound.io/v1beta1
kind: ManagedRedis
metadata:
name: example-redis
namespace: resources-system
spec:
forProvider:
location: East US
resourceGroupName: aks-control-plane
skuName: Balanced_B3
providerConfigRef:
kind: ClusterProviderConfig
name: default
EOF
# Check status
kubectl get managedredis example-redis -n resources-systemkubectl describe provider upbound-provider-family-azure -n resources-system
kubectl logs -n resources-system -l pkg.crossplane.io/provider=provider-azure-
Verify the credentials secret exists and has correct keys:
kubectl get secret azure-crossplane-credentials -n resources-system -o yaml
-
Verify Service Principal has correct permissions:
az ad sp show --id <client-id> az role assignment list --assignee <client-id>
-
Check ClusterProviderConfig status:
kubectl get clusterproviderconfig default -o yaml kubectl describe clusterproviderconfig default
kubectl get clusterproviderconfig default -o yaml
kubectl describe clusterproviderconfig defaultTo remove Crossplane and all related resources:
# Delete managed resources first
kubectl delete managedredis --all -n resources-system
# Terraform will handle the rest
terraform destroy