Skip to content

Commit

Permalink
Add KeyVaultAccessControlClient for data plane RBAC (Azure#13372)
Browse files Browse the repository at this point in the history
  • Loading branch information
chlowell authored and rakshith91 committed Sep 4, 2020
1 parent 1c80ef6 commit 0787c6c
Show file tree
Hide file tree
Showing 11 changed files with 1,107 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,15 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------
__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore
from ._access_control_client import KeyVaultAccessControlClient
from ._internal.client_base import ApiVersion
from ._models import KeyVaultPermission, KeyVaultRoleAssignment, KeyVaultRoleDefinition


__all__ = [
"ApiVersion",
"KeyVaultAccessControlClient",
"KeyVaultPermission",
"KeyVaultRoleAssignment",
"KeyVaultRoleDefinition",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# ------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------
from typing import TYPE_CHECKING

from azure.core.tracing.decorator import distributed_trace

from ._models import KeyVaultRoleAssignment, KeyVaultRoleDefinition
from ._internal import KeyVaultClientBase

if TYPE_CHECKING:
from typing import Any, Union
from uuid import UUID
from azure.core.paging import ItemPaged


class KeyVaultAccessControlClient(KeyVaultClientBase):
"""Manages role-based access to Azure Key Vault.
:param str vault_url: URL of the vault the client will manage. This is also called the vault's "DNS Name".
:param credential: an object which can provide an access token for the vault, such as a credential from
:mod:`azure.identity`
"""

# pylint:disable=protected-access

@distributed_trace
def create_role_assignment(self, role_scope, role_assignment_name, role_definition_id, principal_id, **kwargs):
# type: (str, Union[str, UUID], str, str, **Any) -> KeyVaultRoleAssignment
"""Create a role assignment.
:param str role_scope: scope the role assignment will apply over
:param role_assignment_name: a name for the role assignment. Must be a UUID.
:type role_assignment_name: str or uuid.UUID
:param str role_definition_id: ID of the role's definition
:param str principal_id: Azure Active Directory object ID of the principal which will be assigned the role. The
principal can be a user, service principal, or security group.
:rtype: KeyVaultRoleAssignment
"""
create_parameters = self._client.role_assignments.models.RoleAssignmentCreateParameters(
properties=self._client.role_assignments.models.RoleAssignmentProperties(
principal_id=principal_id, role_definition_id=str(role_definition_id)
)
)
assignment = self._client.role_assignments.create(
vault_base_url=self._vault_url,
scope=role_scope,
role_assignment_name=role_assignment_name,
parameters=create_parameters,
**kwargs
)
return KeyVaultRoleAssignment._from_generated(assignment)

@distributed_trace
def delete_role_assignment(self, role_scope, role_assignment_name, **kwargs):
# type: (str, Union[str, UUID], **Any) -> KeyVaultRoleAssignment
"""Delete a role assignment.
:param str role_scope: the assignment's scope, for example "/", "/keys", or "/keys/<specific key identifier>"
:param role_assignment_name: the assignment's name. Must be a UUID.
:type role_assignment_name: str or uuid.UUID
:returns: the deleted assignment
:rtype: KeyVaultRoleAssignment
"""
assignment = self._client.role_assignments.delete(
vault_base_url=self._vault_url, scope=role_scope, role_assignment_name=str(role_assignment_name), **kwargs
)
return KeyVaultRoleAssignment._from_generated(assignment)

@distributed_trace
def get_role_assignment(self, role_scope, role_assignment_name, **kwargs):
# type: (str, Union[str, UUID], **Any) -> KeyVaultRoleAssignment
"""Get a role assignment.
:param str role_scope: the assignment's scope, for example "/", "/keys", or "/keys/<specific key identifier>"
:param role_assignment_name: the assignment's name. Must be a UUID.
:type role_assignment_name: str or uuid.UUID
:rtype: KeyVaultRoleAssignment
"""
assignment = self._client.role_assignments.get(
vault_base_url=self._vault_url, scope=role_scope, role_assignment_name=str(role_assignment_name), **kwargs
)
return KeyVaultRoleAssignment._from_generated(assignment)

@distributed_trace
def list_role_assignments(self, role_scope, **kwargs):
# type: (str, **Any) -> ItemPaged[KeyVaultRoleAssignment]
"""List all role assignments for a scope.
:param str role_scope: scope of the role assignments
:rtype: ~azure.core.paging.ItemPaged[KeyVaultRoleAssignment]
"""
return self._client.role_assignments.list_for_scope(
self._vault_url,
role_scope,
cls=lambda result: [KeyVaultRoleAssignment._from_generated(a) for a in result],
**kwargs
)

@distributed_trace
def list_role_definitions(self, role_scope, **kwargs):
# type: (str, **Any) -> ItemPaged[KeyVaultRoleDefinition]
"""List all role definitions applicable at and above a scope.
:param str role_scope: scope of the role definitions
:rtype: ~azure.core.paging.ItemPaged[KeyVaultRoleDefinition]
"""
return self._client.role_definitions.list(
self._vault_url,
role_scope,
cls=lambda result: [KeyVaultRoleDefinition._from_generated(d) for d in result],
**kwargs
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# ------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Any


# pylint:disable=protected-access


class KeyVaultPermission(object):
"""Role definition permissions.
:ivar list[str] actions: allowed actions
:ivar list[str] not_actions: denied actions
:ivar list[str] data_actions: allowed data actions
:ivar list[str] not_data_actions: denied data actions
"""

def __init__(self, **kwargs):
# type: (**Any) -> None
self.actions = kwargs.get("actions")
self.not_actions = kwargs.get("not_actions")
self.data_actions = kwargs.get("data_actions")
self.not_data_actions = kwargs.get("not_data_actions")

@classmethod
def _from_generated(cls, permissions):
return cls(
actions=permissions.actions,
not_actions=permissions.not_actions,
data_actions=permissions.data_actions,
not_data_actions=permissions.not_data_actions,
)


class KeyVaultRoleAssignment(object):
"""Represents the assignment to a principal of a role over a scope"""

def __init__(self, **kwargs):
# type: (**Any) -> None
self._assignment_id = kwargs.get("assignment_id")
self._name = kwargs.get("name")
self._properties = kwargs.get("properties")
self._type = kwargs.get("assignment_type")

def __repr__(self):
# type: () -> str
return "KeyVaultRoleAssignment<{}>".format(self._assignment_id)

@property
def assignment_id(self):
# type: () -> str
"""unique identifier for this assignment"""
return self._assignment_id

@property
def name(self):
# type: () -> str
"""name of the assignment"""
return self._name

@property
def principal_id(self):
# type: () -> str
"""ID of the principal this assignment applies to.
This maps to the ID inside the Active Directory. It can point to a user, service principal, or security group.
"""
return self._properties.principal_id

@property
def role_definition_id(self):
# type: () -> str
"""ID of the role's definition"""
return self._properties.role_definition_id

@property
def scope(self):
# type: () -> str
"""scope of the assignment"""
return self._properties.scope

@property
def type(self):
# type: () -> str
"""the type of this assignment"""
return self._type

@classmethod
def _from_generated(cls, role_assignment):
return cls(
assignment_id=role_assignment.id,
name=role_assignment.name,
assignment_type=role_assignment.type,
properties=KeyVaultRoleAssignmentProperties._from_generated(role_assignment.properties),
)


class KeyVaultRoleAssignmentProperties(object):
def __init__(self, **kwargs):
# type: (**Any) -> None
self.principal_id = kwargs.get("principal_id")
self.role_definition_id = kwargs.get("role_definition_id")
self.scope = kwargs.get("scope")

def __repr__(self):
# type: () -> str
return "KeyVaultRoleAssignmentProperties(principal_id={}, role_definition_id={}, scope={})".format(
self.principal_id, self.role_definition_id, self.scope
)[:1024]

@classmethod
def _from_generated(cls, role_assignment_properties):
# the generated RoleAssignmentProperties and RoleAssignmentPropertiesWithScope
# models differ only in that the latter has a "scope" attribute
return cls(
principal_id=role_assignment_properties.principal_id,
role_definition_id=role_assignment_properties.role_definition_id,
scope=getattr(role_assignment_properties, "scope", None),
)


class KeyVaultRoleDefinition(object):
"""Role definition.
:ivar str id: The role definition ID.
:ivar str name: The role definition name.
:ivar str type: The role definition type.
:ivar str role_name: The role name.
:ivar str description: The role definition description.
:ivar str role_type: The role type.
:ivar permissions: Role definition permissions.
:vartype permissions: list[KeyVaultPermission]
:ivar list[str] assignable_scopes: Role definition assignable scopes.
"""

def __init__(self, **kwargs):
# type: (**Any) -> None
self.id = kwargs.get("id")
self.name = kwargs.get("name")
self.role_name = kwargs.get("role_name")
self.description = kwargs.get("description")
self.role_type = kwargs.get("role_type")
self.type = kwargs.get("type")
self.permissions = kwargs.get("permissions")
self.assignable_scopes = kwargs.get("assignable_scopes")

def __repr__(self):
# type: () -> str
return "<KeyVaultRoleDefinition {}>".format(self.role_name)[:1024]

@classmethod
def _from_generated(cls, definition):
return cls(
assignable_scopes=definition.assignable_scopes,
description=definition.description,
id=definition.id,
name=definition.name,
permissions=[KeyVaultPermission._from_generated(p) for p in definition.permissions],
role_name=definition.role_name,
role_type=definition.role_type,
type=definition.type,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------
from ._access_control_client import KeyVaultAccessControlClient

__all__ = ["KeyVaultAccessControlClient"]

0 comments on commit 0787c6c

Please sign in to comment.