Skip to main content
The Microsoft 365 provider can use a Service Principal with a Client Certificate to authenticate to Microsoft 365 services. This is a more secure authentication method compared to client secrets, as certificates are less susceptible to certain types of attacks and can be managed with stronger security controls.

Prerequisites

  • A Microsoft Entra ID tenant
  • Permissions to create an app registration in your tenant
  • Tools for generating certificates (OpenSSL, PowerShell, or other certificate management tools)

Generate a Certificate

# Generate a private key
openssl genrsa -out key.pem 4096

# Generate a certificate signing request (CSR)
openssl req -new -key key.pem -out cert.csr

# Generate a self-signed certificate (valid for 365 days)
openssl x509 -req -days 365 -in cert.csr -signkey key.pem -out cert.pem

# Create a PKCS#12 file that contains both certificate and private key
openssl pkcs12 -export -out cert.pfx -inkey key.pem -in cert.pem -password pass:YourSecurePassword

Setup App Registration

2

Add API Permissions

  • Navigate to “API permissions”
  • Click “Add a permission” and select “Microsoft Graph”
  • Choose “Application permissions” for automation scenarios
  • Apply least privilege principles
  • Click “Grant admin consent”
3

Upload Certificate

  • Navigate to “Certificates & secrets” in your app registration
  • In the “Certificates” section, click “Upload certificate”
  • Upload your public certificate (.cer or .pem) file
  • Add a description and expiration date

Provider Configuration

Certificate Management

Certificate Rotation

1

Generate New Certificate

Create a new certificate following the generation methods above
2

Upload to App Registration

Upload the new certificate to your Entra ID app registration. Both old and new certificates can be active simultaneously.
3

Update Configuration

Update your Terraform configuration or environment variables to use the new certificate
4

Remove Old Certificate

After confirming the new certificate works, optionally remove the old certificate from the app registration
Set up a pipeline job to regularly scan for certificate expiration to ensure you have sufficient time to perform rotation.

Certificate Storage Options

Azure Key Vault

Store certificates in Azure Key Vault and retrieve during Terraform execution

HashiCorp Vault

Use Vault’s PKI engine for certificate management and rotation

Secure File Storage

Ensure certificate files have restrictive permissions (chmod 600)

CI/CD Secrets

Store certificates in your CI/CD pipeline’s secure secret storage

Using Azure Key Vault

# Retrieve certificate from Azure Key Vault
data "azurerm_key_vault" "example" {
  name                = "my-keyvault"
  resource_group_name = "my-resource-group"
}

data "azurerm_key_vault_certificate" "example" {
  name         = "my-certificate"
  key_vault_id = data.azurerm_key_vault.example.id
}

provider "microsoft365" {
  auth_method = "client_certificate"
  tenant_id   = var.tenant_id
  entra_id_options = {
    client_id                   = var.client_id
    client_certificate          = data.azurerm_key_vault_certificate.example.certificate_data_base64
    client_certificate_password = ""
  }
}

HashiCorp Vault Integration

Store Certificates in Vault

# Store tenant_id and client_id
vault kv put secret/microsoft365/credentials \
  tenant_id="00000000-0000-0000-0000-000000000000" \
  client_id="00000000-0000-0000-0000-000000000000"

# Store certificate (base64 encoded)
vault kv put secret/microsoft365/certificate \
  certificate="$(base64 -i /path/to/certificate.pfx)" \
  password="YourSecurePassword"

Retrieve with Vault Provider

data "vault_kv_secret_v2" "microsoft365_creds" {
  mount = "secret"
  name  = "microsoft365/credentials"
}

data "vault_kv_secret_v2" "microsoft365_cert" {
  mount = "secret"
  name  = "microsoft365/certificate"
}

resource "local_file" "certificate" {
  content_base64  = data.vault_kv_secret_v2.microsoft365_cert.data["certificate"]
  filename        = "${path.module}/temp_certificate.pfx"
  file_permission = "0600"
}

provider "microsoft365" {
  auth_method = "client_certificate"
  tenant_id   = data.vault_kv_secret_v2.microsoft365_creds.data["tenant_id"]
  entra_id_options = {
    client_id                   = data.vault_kv_secret_v2.microsoft365_creds.data["client_id"]
    client_certificate          = local_file.certificate.filename
    client_certificate_password = data.vault_kv_secret_v2.microsoft365_cert.data["password"]
  }
}

Security Considerations

Certificate Security Best Practices
  • Use strong passwords for PKCS#12 (.pfx) files
  • Protect private keys and certificates with proper file permissions
  • Never commit certificates or private keys to version control
  • Use certificates with reasonable expiration periods (typically 1-2 years)
  • Consider using HSMs for storing certificate private keys in high-security environments
  • For maximum security, use certificates from a trusted Certificate Authority rather than self-signed

Troubleshooting

Verify the tenant ID, client ID, and certificate details are correct. Ensure the certificate hasn’t expired.
Ensure the certificate is properly formatted and uploaded to the app registration. The public key must be uploaded to Entra ID.
Ensure your certificate is in PKCS#12 format (.pfx or .p12). Convert if necessary using OpenSSL.
If you’re having authentication problems, try setting send_certificate_chain to true.
Enable debug mode for detailed logging:
export M365_DEBUG_MODE="true"
Or in Terraform:
provider "microsoft365" {
  debug_mode = true
}

Build docs developers (and LLMs) love