
Getty Images/iStockphoto
Why and how to create Azure service principals
Service principals are a convenient and secure way to protect Azure resources. Follow this step-by-step guide to create a service principal that defends vital Azure workloads.
Hardcoded passwords have long been a standard in basic security and authentication practices. However, businesses and enterprises that manage critical data require further layers of security.
In Azure, service principals are a core part of access control management for applications and automation-related tasks. They represent a form of identity that applications or services use to authenticate and access specific resources in Azure. This helps secure interactions within a cloud environment.
Service principals are the modern replacement for the traditional service account that provides security context for specific services. With these principals, access to vital services can be much more fine-grained than a traditional account. Conveniently, principals can also enable access to resources without users needing to memorize or store passwords.
Learn the basic steps to create an Azure service principal, and learn about other security identities that can protect valuable resources.
Create an Azure service principal
Let's walk through an example to better understand how Azure service principals function.
When creating a service principal, begin by registering an app in Microsoft Entra ID, which generates a unique application ID. Registration defines the application's identity in Entra ID and is the foundation for creating a service principal.
An Azure service principal consists of several discrete fields, such as the following:
- Application ID. This serves as a unique identifier for the service principal within Entra ID.
- Directory ID. A representation of the Entra ID instance the service principal was created under.
- Client secrets and certificates. The credential the application uses to authenticate itself when calling Azure resources. Certificates are usually preferred over client secrets as they are harder to compromise.
- Role assignments. Role-based access control (RBAC) assigns specific roles to the service principal, defining what it can access. Common roles include Contributor, Reader and Owner.
- Environmental variables. These store credentials in pipelines or automation scripts.
Once these fields have been completed, users can deploy their Terraform plan. Be sure to delete the plan when done. Unless users intend to maintain their resource or service principal, they should delete it after use so they don't incur further charges through Azure.
Let's create an Azure service principal to deploy a Terraform plan and create a basic VM using the Azure CLI and the Terraform app. Ensure that both are installed locally.
Step 1. Create the service principal
Create an Azure service principal with the Azure CLI. Start the CLI from the command line, and log in to Azure using the command az login.
Once logged in, create the service principal with the following command:
az ad sp create-for-rbac --name "myServicePrincipal" -- role Contributor -- scopes /subscriptions/<SUBSCRIPTION_ID>
Replace <SUBSCRIPTION_ID> with the appropriate subscription ID.
This command outputs the following key information:
- AppId. The application ID.
- Password. A client secret for this example for brevity.
- Tenant. The directory ID.

Save this information because you will need this information again to configure Terraform in the system. Verify the service principal using the appId that was provided in the previous command:
az ad sp show --id <appId>
This shows information about the service principal application ID.
Step 2. Set up environment variables
To enable Terraform to authenticate with Azure, set the following environment variables:
export ARM_CLIENT_ID="<appId>"
export ARM_CLIENT_SECRET="<password>"
export ARM_SUBSCRIPTION_ID="<SUBSCRIPTION_ID>"
export ARM_TENANT_ID="<tenant>"
Replace <appId>, <password>, <SUBSCRIPTION_ID> and <tenant> with the values from the output of the service principal creation earlier. This exposes those items as a variable so that Terraform can read them.
Step 3. Deploy a VM using Terraform
Create a new folder for the Terraform configuration file. Copy and paste the below data into a file and save it as main.tf file.
hcl
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "East US"
}
resource "azurerm_virtual_network" "example" {
name = "example-network"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
}
resource "azurerm_subnet" "example" {
name = "example-subnet"
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = ["10.0.1.0/24"]
}
resource "azurerm_network_interface" "example" {
name = "example-nic"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.example.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_linux_virtual_machine" "example" {
name = "example-vm"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
size = "Standard_DS1_v2"
network_interface_ids = [
azurerm_network_interface.example.id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "22.04-LTS"
version = "latest"
}
admin_username = "azureuser"
admin_ssh_key { username = "azureuser" public_key = file("~/.ssh/id_rsa.pub") # Path to your public key }
admin_password = "P@ssw0rd1234!" # Choose a strong password
}
To deploy it, use the same terminal window as before. Navigate to the newly created Terraform folder, and run the following command: terraform init. This command prepares the file and checks that it is properly formatted.

The next stage is for Terraform to review and apply the configuration. Use the command terraform plan.
Finally, assuming no errors, apply the Terraform configuration using the command terraform apply.

The administrator needs to confirm the deployment. Confirm the prompt to proceed with deployment by typing yes. Terraform starts creating the resources as defined in the file.
Once Terraform deploys, an output message displays showing the VM's IP address. Verify the VM in the Azure portal. The administrator should be able to log in via SSH using the key pair included in the Terraform file. Below is the output of the Terraform plan from this example.

Remember, running resources in Azure costs money. Ensure that any unused resources are deleted after use to avoid further charges. Using Terraform and service principals, the administrator can destroy the resources with the terraform destroy command.
Confirm when prompted, and Terraform removes all resources defined in the main.tf file.
Azure service principals vs. managed identities
Service principals are just one form of security identity in Azure -- another is managed identities. They provide an identity to applications that access Azure resources. Both service principals and managed identities enable granular, programmatic access to Azure infrastructure without putting passwords into scripts.
Managed identities can be system-assigned or user-assigned. With system-assigned managed identities, admins create an identity as a part of a specific Azure resource, such as a VM. That identity shares a lifecycle with its associated resource. When an admin deletes the resource, they also delete the identity. User-assigned identities, on the other hand, are not tied to a specific resource. They have their own lifecycle and can be shared across resources.
The key difference between Azure service principals and managed identities is that, with the latter, admins do not have to manage credentials, including passwords.
To create a managed identity, go to the Azure portal, and navigate to the managed identity blade. Then, assign a role to the identity. From here, administrators can also set the duration of validity for a managed identity.
Editor's note: This article was updated to reflect changes in the best practices for creating Azure service principals.
Stuart Burns is an enterprise Linux administrator at a leading company that specializes in catastrophe and disaster modeling.