Automating EntraID onboarding in Veeam
Disclaimer:
I’m not a professional developer, and this script was created on a beta build of the software. It is intended to demonstrate the “art of the possible” rather than serve as production-ready code. Use this example with caution, and test thoroughly in your environment before relying on it for critical tasks. Please see the Gitlab repo for the full subset of code as these are just snippets to show the process.
Introduction
As organizations continue to scale, automation becomes essential for managing complex infrastructures efficiently. With the release of version 12.3 of Veeam Backup & Replication, a set of new APIs for EntraID is available. These APIs simplify onboarding EntraID customers, allowing service providers to automate tenant creation and streamline setup processes.
Directory Structure
Here’s the layout of my project directory:
.
├── README.md
├── device_code.py
├── entra.py
├── list_repos.py
├── main.py
├── requirements.txt
├── veeamAuth.py
└── .env
Workflow
-
Authenticate with the Veeam Backup and Replication (VBR) Server
Obtain a bearer token using the/api/oauth2/token
endpoint. -
Retrieve a List of Repositories
Access the list of repositories via/api/v1/backupInfrastructure/repositories
. This step is essential to get the ID of the required repository for caching. -
Generate a Device Code
Use the/api/v1/cloudCredentials/appRegistration
endpoint to obtain a device code, which will enable user authentication with Microsoft. -
Authenticate with Microsoft using the Device Code
The customer must authenticate using the provided device code to authorize Veeam’s access. -
Create an EntraID Tenant in VBR
Complete the process by creating an EntraID tenant in VBR via the/api/v1/inventory/entraId/tenants
endpoint.
Note: As you may have noticed, this workflow requires a manual step in the middle: much like the process for authenticating Microsoft 365, we need to authorize Veeam to create the necessary app registrations. While this step could potentially be integrated into a custom portal for service providers, for now, the process involves opening a browser tab to complete the authentication.
Step 1
First, we need to authenticate with the Veeam Backup and Replication server. We can achieve this by obtaining a bearer token via the /api/oauth2/token
endpoint, passing through a username and password.
def authenticate(veeam_server, username, password, api_version):
"""Authenticate to Veeam server and return session token."""
url = f"{veeam_server}/api/oauth2/token"
headers = {"Content-Type": "application/x-www-form-urlencoded", "x-api-version": api_version}
data = {"grant_type": "password", "username": username, "password": password}
response = requests.post(url, headers=headers, data=data, verify=False)
if response.status_code == 200:
return response.json().get('access_token')
else:
print(f"Authentication failed: {response.status_code} - {response.text}")
return None
Step 2
In this step, we need to retrieve a list of repositories and grab the repository ID, which is required for the Entra API call.
# Function to list repositories by calling the API
def list_repos(veeam_server, api_version, token):
url = f"{veeam_server}/api/v1/backupInfrastructure/repositories"
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"x-api-version": api_version,
"Authorization": f"bearer {token}"
}
try:
response = requests.get(url, headers=headers, verify=False)
response.raise_for_status()
# Debugging: Print status and content to ensure we’re getting a valid response
print("Status Code:", response.status_code)
print("Response Content:", response.text)
# Parse and return repository data correctly
repos_data = response.json().get('data', [])
return [{"id": repo['id'], "name": repo['name']} for repo in repos_data]
except requests.exceptions.RequestException as e:
print(f"Request error: {e}")
return []
Step 3
In this step, we need to generate a device code. This part can be a bit confusing because, while we aim to automate the entire process, full automation isn’t strictly possible. We require the customer to authenticate themselves to grant Veeam permission to create the necessary app registration.
By generating a device code, we enable the customer to authenticate manually, ensuring they provide the needed authorization for the process to proceed.
def get_devicecode(veeam_server, api_version, token):
url = f"{veeam_server}/api/v1/cloudCredentials/appRegistration"
data = {"type": "AzureCompute", "region": "Global"}
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"x-api-version": api_version,
"Authorization": f"bearer {token}"
}
print("getting device code")
print(url)
print(data)
print(headers)
try:
response = requests.post(url, json=data, headers=headers, verify=False)
response.raise_for_status()
json_data = response.json()
print(json_data)
if "verificationCode" in json_data:
return json_data["verificationCode"]
else:
print("Error: 'verificationCode' not found.")
return None
except requests.exceptions.RequestException as e:
print(f"Request error: {e}")
return None
Step 4
Now that we have everything we need, we can pull it all together in the EntraID API call to create the tenant.
In this step, we are performing two main actions:
-
Authentication
Since the customer needs to authenticate, we will open a browser session to the Microsoft device login page and provide them with a device login code. The customer will enter this code to validate their authentication. -
API Call to VBR Server
Next, we will make the required API call to the VBR server. This call will remain in a waiting state for a set period until it receives authorization confirmation from Microsoft. This is why the first step is necessary: after initiating the API call, it will wait until the customer has successfully authenticated. Once authentication is confirmed, the API call will complete successfully, adding the EntraID tenant.
def add_entraIDTenant(tenantId, veeam_server, api_version, token, cache_repo_id, verification_code):
"""
Adds an Entra ID tenant to the Veeam backup server.
Parameters:
tenantId (str): The tenant ID to be added.
veeam_server (str): URL of the Veeam server.
api_version (str): API version for the request.
token (str): Authorization token for Veeam server.
cache_repo_id (str): ID of the repository to be used.
verification_code (str): Device code provided by the user after authentication.
Returns:
response (requests.Response): Response object from the POST request.
"""
url = f"{veeam_server}/api/v1/inventory/entraId/tenants"
headers = {
"Content-Type": "application/json",
"x-api-version": api_version,
"Authorization": f"bearer {token}"
}
payload = {
"tenantId": tenantId,
"description": "Created by Python",
"cacheRepositoryId": cache_repo_id,
"region": "Global",
"creationMode": "newAccount",
"newAccount": {"verificationCode": verification_code}
}
try:
response = requests.post(url, headers=headers, json=payload, verify=False)
print("Response Status Code:", response.status_code)
print("Response Content:", response.text)
return response # Return the response object for status checking
except requests.RequestException as e:
print(f"Request error: {e}")
return None # Return None if there’s an exception
Fantastic! After running the script and successfully authenticating with the device code, we have a successful entry in VBR.
Conclusion
Automating EntraID onboarding with Veeam’s API simplifies the onboarding process and can save significant time, especially for large organizations with frequent tenant provisioning needs. By leveraging this Python script, administrators can streamline the process, reducing the need for repetitive setup tasks and manual interventions. While this guide outlines a fundamental approach, there’s plenty of room for customization to suit specific requirements.
Hopefully, this provides a solid foundation to build from! I hope you found this guide helpful. As always, keep on learning!