I'm trying to create a keyvault with Python by running the code from here:
import os
import json
from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.keyvault import KeyVaultManagementClient
from azure.mgmt.resource.resources import ResourceManagementClient
from haikunator import Haikunator
haikunator = Haikunator()
WEST_US = "westus"
GROUP_NAME = "azure-sample-group"
KV_NAME = haikunator.haikunate()
# The object ID of the User or Application for access policies. Find this number in the portal
OBJECT_ID = "401e9294-xxxx-xxxx-xxxx-xxxx"
# Manage resources and resource groups - create, update and delete a resource group,
# deploy a solution into a resource group, export an ARM template. Create, read, update
# and delete a resource
#
# This script expects that the following environment vars are set:
#
# AZURE_TENANT_ID: with your Azure Active Directory tenant id or domain
# AZURE_CLIENT_ID: with your Azure Active Directory Application Client ID
# AZURE_CLIENT_SECRET: with your Azure Active Directory Application Secret
# AZURE_SUBSCRIPTION_ID: with your Azure Subscription Id
#
def run_example():
"""Resource Group management example."""
#
# Create the Resource Manager Client with an Application (service principal) token provider
#
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]
credentials = ServicePrincipalCredentials(
client_id=os.environ["AZURE_CLIENT_ID"],
secret=os.environ["AZURE_CLIENT_SECRET"],
tenant=os.environ["AZURE_TENANT_ID"],
)
kv_client = KeyVaultManagementClient(credentials, subscription_id)
resource_client = ResourceManagementClient(credentials, subscription_id)
# You MIGHT need to add KeyVault as a valid provider for these credentials
# If so, this operation has to be done only once for each credentials
resource_client.providers.register("Microsoft.KeyVault")
# Create Resource group
print("\nCreate Resource Group")
resource_group_params = {"location": WEST_US}
print_item(
resource_client.resource_groups.create_or_update(
GROUP_NAME, resource_group_params
)
)
# Create a vault
print("\nCreate a vault")
vault = kv_client.vaults.create_or_update(
GROUP_NAME,
KV_NAME,
{
"location": WEST_US,
"properties": {
"sku": {"name": "standard"},
"tenant_id": os.environ["AZURE_TENANT_ID"],
"access_policies": [
{
"tenant_id": os.environ["AZURE_TENANT_ID"],
"object_id": OBJECT_ID,
"permissions": {"keys": ["all"], "secrets": ["all"]},
}
],
},
},
)
print_item(vault)
# List the Key vaults
print("\nList KeyVault")
for vault in kv_client.vaults.list():
print_item(vault)
# Delete Resource group and everything in it
print("\nDelete Resource Group")
delete_async_operation = resource_client.resource_groups.delete(GROUP_NAME)
delete_async_operation.wait()
print("\nDeleted: {}".format(GROUP_NAME))
def print_item(group):
"""Print an instance."""
print("\tName: {}".format(group.name))
print("\tId: {}".format(group.id))
print("\tLocation: {}".format(group.location))
print("\tTags: {}".format(group.tags))
if __name__ == "__main__":
run_example()
After receiving comments, I assigned the Contribute
role to the service principal.
My only modification to the code was substituting the object id with the one from my service principal (see image below):
I'm receiving following error:
EDIT: Accepted @sridev's answer because I solved the issue by running the sample code which was linked in the comments
Here's my working code, based on this GitHub repo, assuming that the Azure environment variables are set properly:
import os
from azure.identity import DefaultAzureCredential
from azure.mgmt.keyvault import KeyVaultManagementClient
from azure.mgmt.resource import ResourceManagementClient
def main():
TENANT_ID = os.environ.get("AZURE_TENANT_ID", None)
SUBSCRIPTION_ID = os.environ.get("AZURE_SUBSCRIPTION_ID", None)
GROUP_NAME = "resource_group_name"
VAULT = "vault_name"
LOCATION = "azure_location_eg_westus"
OBJECT_ID = "service_principal_object_id"
# Create client
# Other authentication approaches: https://pypi.org/project/azure-identity/
resource_client = ResourceManagementClient(
credential=DefaultAzureCredential(), subscription_id=SUBSCRIPTION_ID
)
keyvault_client = KeyVaultManagementClient(
credential=DefaultAzureCredential(), subscription_id=SUBSCRIPTION_ID
)
# Create resource group
resource_client.resource_groups.create_or_update(GROUP_NAME, {"location": LOCATION})
# Create vault
vault = keyvault_client.vaults.begin_create_or_update(
GROUP_NAME,
VAULT,
{
"location": LOCATION,
"properties": {
"tenant_id": TENANT_ID,
"sku": {"family": "A", "name": "standard"},
"access_policies": [
{
"tenant_id": TENANT_ID,
"object_id": OBJECT_ID,
"permissions": {
"keys": [
"encrypt",
"decrypt",
"wrapKey",
"unwrapKey",
"sign",
"verify",
"get",
"list",
"create",
"update",
"import",
"delete",
"backup",
"restore",
"recover",
"purge",
],
"secrets": [
"get",
"list",
"set",
"delete",
"backup",
"restore",
"recover",
"purge",
],
},
}
],
"enabled_for_deployment": True,
"enabled_for_disk_encryption": True,
"enabled_for_template_deployment": True,
},
},
).result()
print("Create vault:\n{}".format(vault))
# Get vault
vault = keyvault_client.vaults.get(GROUP_NAME, VAULT)
print("Get vault:\n{}".format(vault))
# Update vault
vault = keyvault_client.vaults.update(
GROUP_NAME, VAULT, {"tags": {"category": "Marketing"}}
)
print("Update vault:\n{}".format(vault))
# Delete vault
keyvault_client.vaults.delete(GROUP_NAME, VAULT)
print("Delete vault.\n")
# Purge a deleted vault
keyvault_client.vaults.begin_purge_deleted(VAULT, LOCATION).result()
print("Purge a deleted vault.\n")
# Delete Group
resource_client.resource_groups.begin_delete(GROUP_NAME).result()
if __name__ == "__main__":
main()
The error usually occurs if your service principal don't have sufficient permissions or roles to perform the operation.
I tried to reproduce the same in my environment and got below results:
I registered one web application named SriApp
in my Azure AD tenant like below:
When I ran the below code without assigning any RBAC role to above servie principal, I got same error as below:
import os
import json
from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.keyvault import KeyVaultManagementClient
from azure.mgmt.resource.resources import ResourceManagementClient
from haikunator import Haikunator
haikunator = Haikunator()
WEST_US = 'Germany West Central'
GROUP_NAME = 'azure-sample-resources'
KV_NAME = haikunator.haikunate()
# The object ID of the User or Application for access policies. Find this number in the portal
OBJECT_ID = 'bfc7171d-8c25-4b41-9764-xxxxxxxxxxx'
def run_example():
"""Resource Group management example."""
#
# Create the Resource Manager Client with an Application (service principal) token provider
#
subscription_id = '124c97c3-58a7-4eb5-ac50-xxxxxxxxxx'
credentials = ServicePrincipalCredentials(
client_id='794cb163-ca1c-4fec-b7df-xxxxxxxxxxxx',
secret='xxxxxxxxxxxxxxxxxxxxxx',
tenant='6c3f1c39-b84c-4188-b49f-xxxxxxxxx'
)
kv_client = KeyVaultManagementClient(credentials, subscription_id)
resource_client = ResourceManagementClient(credentials, subscription_id)
# You MIGHT need to add KeyVault as a valid provider for these credentials
# If so, this operation has to be done only once for each credentials
resource_client.providers.register('Microsoft.KeyVault')
# Create Resource group
print('\nCreate Resource Group')
resource_group_params = {'location': WEST_US}
print_item(resource_client.resource_groups.create_or_update(
GROUP_NAME, resource_group_params))
# Create a vault
print('\nCreate a vault')
vault = kv_client.vaults.create_or_update(
GROUP_NAME,
KV_NAME,
{
'location': WEST_US,
'properties': {
'sku': {
'name': 'standard'
},
'tenant_id': '6c3f1c39-b84c-4188-b49f-xxxxxxxxx',
'access_policies': [{
'tenant_id': '6c3f1c39-b84c-4188-b49f-xxxxxxxx',
'object_id': OBJECT_ID,
'permissions': {
'keys': ['all'],
'secrets': ['all']
}
}]
}
}
)
print_item(vault)
# List the Key vaults
print('\nList KeyVault')
for vault in kv_client.vaults.list():
print_item(vault)
# Delete Resource group and everything in it
# print('\nDelete Resource Group')
# delete_async_operation = resource_client.resource_groups.delete(GROUP_NAME)
# delete_async_operation.wait()
# print("\nDeleted: {}".format(GROUP_NAME))
def print_item(group):
"""Print an instance."""
print("\tName: {}".format(group.name))
print("\tId: {}".format(group.id))
print("\tLocation: {}".format(group.location))
print("\tTags: {}".format(group.tags))
if __name__ == "__main__":
run_example()
Response
To resolve the error, you need to assign Contributor
role to the service principal under your subscription like below:
Go to Azure Portal -> Your Subscription -> Access control (IAM) -> Add role assignment -> Contributor
After assigning the role, I ran the code again and got response successfully like below:
import os
import json
from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.keyvault import KeyVaultManagementClient
from azure.mgmt.resource.resources import ResourceManagementClient
from haikunator import Haikunator
haikunator = Haikunator()
WEST_US = 'Germany West Central'
GROUP_NAME = 'azure-sample-resources'
KV_NAME = haikunator.haikunate()
# The object ID of the User or Application for access policies. Find this number in the portal
OBJECT_ID = 'bfc7171d-8c25-4b41-9764-xxxxxxxxxxx'
def run_example():
"""Resource Group management example."""
#
# Create the Resource Manager Client with an Application (service principal) token provider
#
subscription_id = '124c97c3-58a7-4eb5-ac50-xxxxxxxxxx'
credentials = ServicePrincipalCredentials(
client_id='794cb163-ca1c-4fec-b7df-xxxxxxxxxxxx',
secret='xxxxxxxxxxxxxxxxxxxxxx',
tenant='6c3f1c39-b84c-4188-b49f-xxxxxxxxx'
)
kv_client = KeyVaultManagementClient(credentials, subscription_id)
resource_client = ResourceManagementClient(credentials, subscription_id)
# You MIGHT need to add KeyVault as a valid provider for these credentials
# If so, this operation has to be done only once for each credentials
resource_client.providers.register('Microsoft.KeyVault')
# Create Resource group
print('\nCreate Resource Group')
resource_group_params = {'location': WEST_US}
print_item(resource_client.resource_groups.create_or_update(
GROUP_NAME, resource_group_params))
# Create a vault
print('\nCreate a vault')
vault = kv_client.vaults.create_or_update(
GROUP_NAME,
KV_NAME,
{
'location': WEST_US,
'properties': {
'sku': {
'name': 'standard'
},
'tenant_id': '6c3f1c39-b84c-4188-b49f-xxxxxxxxx',
'access_policies': [{
'tenant_id': '6c3f1c39-b84c-4188-b49f-xxxxxxxx',
'object_id': OBJECT_ID,
'permissions': {
'keys': ['all'],
'secrets': ['all']
}
}]
}
}
)
print_item(vault)
# List the Key vaults
print('\nList KeyVault')
for vault in kv_client.vaults.list():
print_item(vault)
# Delete Resource group and everything in it
# print('\nDelete Resource Group')
# delete_async_operation = resource_client.resource_groups.delete(GROUP_NAME)
# delete_async_operation.wait()
# print("\nDeleted: {}".format(GROUP_NAME))
def print_item(group):
"""Print an instance."""
print("\tName: {}".format(group.name))
print("\tId: {}".format(group.id))
print("\tLocation: {}".format(group.location))
print("\tTags: {}".format(group.tags))
if __name__ == "__main__":
run_example()
Response:
To confirm that, I checked the same in Portal where key vault created successfully under new resource group with Location as Germany West Central
like below:
When I checked Access policies of this key vault, it has application added to it with permissions as below: