def create_update_roledefinition(self):
        '''
        Creates or updates role definition.

        :return: deserialized role definition
        '''
        self.log("Creating / Updating role definition {0}".format(self.name))

        try:
            permissions = None
            if self.permissions:
                permissions = [AuthorizationManagementClient.models("2018-01-01-preview").Permission(
                    actions=p.get('actions', None),
                    not_actions=p.get('not_actions', None),
                    data_actions=p.get('data_actions', None),
                    not_data_actions=p.get('not_data_actions', None)
                ) for p in self.permissions]
            role_definition = AuthorizationManagementClient.models("2018-01-01-preview").RoleDefinition(
                role_name=self.name,
                description=self.description,
                permissions=permissions,
                assignable_scopes=self.assignable_scopes,
                role_type='CustomRole')
            if self.role:
                role_definition.name = self.role['name']
            response = self._client.role_definitions.create_or_update(role_definition_id=self.role['name'] if self.role else str(uuid.uuid4()),
                                                                      scope=self.scope,
                                                                      role_definition=role_definition)
            if isinstance(response, LROPoller) or isinstance(response, AzureOperationPoller):
                response = self.get_poller_result(response)

        except CloudError as exc:
            self.log('Error attempting to create role definition.')
            self.fail("Error creating role definition: {0}".format(str(exc)))
        return roledefinition_to_dict(response)
Example #2
0
 def __init__(self, graphrbac_credentials, credentials, tenant_id,
              subscription_id):
     self._subscription_id = subscription_id
     self._client = GraphRbacManagementClient(graphrbac_credentials,
                                              tenant_id=tenant_id)
     self._authorization_client = AuthorizationManagementClient(
         credentials, subscription_id=subscription_id)
Example #3
0
def _query_rbac(ctx: Context, sub: Subscription):
    logger.info(
        f"Enumerating rbac permissions for subscription: {sub.subscription_id}"
    )
    auth_client = AuthorizationManagementClient(ctx.cred_msrest,
                                                sub.subscription_id,
                                                base_url=ctx.cloud["ARM"])
    roles = []
    for role in auth_client.role_assignments.list():
        try:
            role_dict = role.as_dict()
            definition = auth_client.role_definitions.get_by_id(
                role.role_definition_id)
            role_dict["permissions"] = [
                p.as_dict() for p in definition.permissions
            ]
            role_dict["roleName"] = definition.role_name
            role_dict["roleType"] = definition.role_type
            role_dict["roleDescription"] = definition.description
            roles.append(role_dict)
        except Exception as ex:
            logger.error(ex)
    logger.info(
        f"Finishing rbac permissions for subscription: {sub.subscription_id}")
    return roles
Example #4
0
def create_role_assignment(credentials, subscription_id, scope, principal_id):
    """
        Gives service principal contributor role authorization on scope
        :param credentials: msrestazure.azure_active_directory.AdalAuthentication
        :param subscription_id: str
        :param scope: str
        :param principal_id: str
    """
    authorization_client = AuthorizationManagementClient(
        credentials, subscription_id)
    role_name = 'Contributor'
    roles = list(
        authorization_client.role_definitions.list(
            scope, filter="roleName eq '{}'".format(role_name)))
    contributor_role = roles[0]
    for i in range(10):
        try:
            authorization_client.role_assignments.create(
                scope, uuid.uuid4(), {
                    'role_definition_id': contributor_role.id,
                    'principal_id': principal_id
                })
            break
        except CloudError as e:
            # ignore error if service principal has not yet been created
            time.sleep(1)
            if i == 10:
                raise e
Example #5
0
    def __assignReaderRoleToSubscription(self, subscriptionId):

        authorizationClient = AuthorizationManagementClient(
            self.__credentialsProvider.getManagementCredentials(),
            subscriptionId)
        servicePrincipalId = self.getServicePrincipalId()
        if servicePrincipalId == None:
            raise Exception("Could not find servicePrincipal")

        roleDefinitionId = self.__getRoleDefinitionId(subscriptionId,
                                                      authorizationClient)

        roleAssignment = self.__getRoleAssignments(subscriptionId,
                                                   servicePrincipalId,
                                                   roleDefinitionId,
                                                   authorizationClient)
        if roleAssignment != None:
            log.info("Role Assignment already Present for Subscription Id: " +
                     subscriptionId)
            return roleAssignment

        roleAssignmentProperties = RoleAssignmentCreateParameters(
            role_definition_id=roleDefinitionId,
            principal_id=self.getServicePrincipalId())
        return self.__createRoleAssignmentWithRetry(subscriptionId,
                                                    roleAssignmentProperties,
                                                    authorizationClient)
    def run(self, args):
        """Run the remediation job.
        :param args: List of arguments provided to the job.
        :type args: list.
        :returns: int
        """
        params = self.parse(args[1])

        client_id = os.environ.get("AZURE_CLIENT_ID")
        client_secret = os.environ.get("AZURE_CLIENT_SECRET")
        tenant_id = os.environ.get("AZURE_TENANT_ID")
        key_vault_name = params["key_vault_name"]

        # credential for Key Vault management client
        credential = ClientSecretCredential(
            client_id=client_id,
            client_secret=client_secret,
            tenant_id=tenant_id,
        )

        # credential for AzureGraphRbacManagementClient
        credentials = ServicePrincipalCredentials(
            client_id=client_id,
            secret=client_secret,
            tenant=tenant_id,
            resource="https://graph.windows.net",
        )

        keyvault_client = KeyVaultManagementClient(credential,
                                                   params["subscription_id"])

        graph_client = GraphRbacManagementClient(credentials,
                                                 tenant_id,
                                                 base_url=None)

        secret_client = SecretClient(
            vault_url=f"https://{key_vault_name}.vault.azure.net/",
            credential=credential,
        )

        client_authorization = AuthorizationManagementClient(
            credential,
            params["subscription_id"],
            api_version="2018-01-01-preview")

        return self.remediate(
            tenant_id,
            client_id,
            secret_client,
            keyvault_client,
            graph_client,
            client_authorization,
            params["resource_group_name"],
            params["key_vault_name"],
            params["secret_name"],
            params["subscription_id"],
        )
Example #7
0
def connect():
    """Set up Azure Login Credentials from Environmental Variables."""
    credentials = ServicePrincipalCredentials(
        client_id=os.environ.get('ARM_CLIENT_ID'),
        secret=os.environ.get('ARM_CLIENT_SECRET'),
        tenant=os.environ.get('ARM_TENANT_ID')
    )

    # network_client = NetworkManagementClient(credentials, os.environ.get('ARM_SUBSCRIPTION_ID'))
    auth_management_client = AuthorizationManagementClient(credentials,
                                                           os.environ.get('ARM_SUBSCRIPTION_ID'),
                                                           api_version=None, base_url=None)
    return auth_management_client
Example #8
0
 def delete_keylistrole_appservice(self, resource_group_name, storage_name,
                                   role_assignment_name):
     resource_provider = "Microsoft.Storage"
     resource_type = "storageAccounts"
     scope = '/subscriptions/%s/resourceGroups/%s/providers/%s/%s/%s' % (
         self.subscription_id, resource_group_name, resource_provider,
         resource_type, storage_name)
     auth_cli = AuthorizationManagementClient(self.credentials,
                                              self.subscription_id,
                                              api_version="2015-07-01")
     resp = auth_cli.role_assignments.delete(scope, role_assignment_name)
     print("%s App Service access revoked %s Storage account" %
           (role_assignment_name, storage_name))
Example #9
0
def get_role_id_by_name(name, scope=""):
    config = authorization.get_client_config()
    client_token = authorization.get_client_token()
    client = AuthorizationManagementClient(TokenCred(client_token.token),
                                           config.subscription_id)
    def_pages = client.role_definitions.list(scope,
                                             filter=f'roleName eq {name}')
    role = None
    for x in def_pages:
        role = x.id
        break
    if role is None:
        raise Exception(f'role \'{name}\' not found at scope \'{scope}\'')
    return role
Example #10
0
    def __init__(self):
        if os.environ.get('AZURE_SUBSCRIPTION_ID') is not None:
            self.subscription_id = os.environ.get(
                'AZURE_SUBSCRIPTION_ID')  # your Azure Subscription Id
        else:
            raise ValueError(
                'AZURE_SUBSCRIPTION_ID environment variable missing')

        # Sanity check
        if os.environ.get('AZURE_CLIENT_ID') is None:
            raise ValueError('AZURE_CLIENT_ID environment variable missing')
        if os.environ.get('AZURE_CLIENT_SECRET') is None:
            raise ValueError(
                'AZURE_CLIENT_SECRET environment variable missing')
        if os.environ.get('AZURE_TENANT_ID') is None:
            raise ValueError('AZURE_TENANT_ID environment variable missing')
        if os.environ.get('STORAGE_ACCOUNT_NAME') is None:
            raise ValueError(
                'STORAGE_ACCOUNT_NAME environment variable missing')

        self.storage_account_name = os.environ['STORAGE_ACCOUNT_NAME']

        self.credentials = ServicePrincipalCredentials(
            client_id=os.environ['AZURE_CLIENT_ID'],
            secret=os.environ['AZURE_CLIENT_SECRET'],
            tenant=os.environ['AZURE_TENANT_ID'])

        #FIXME do we need two credentials?
        self.client_secret_credential = ClientSecretCredential(
            os.environ['AZURE_TENANT_ID'], os.environ['AZURE_CLIENT_ID'],
            os.environ['AZURE_CLIENT_SECRET'])

        self.resource_client = ResourceManagementClient(
            self.credentials, self.subscription_id)
        self.msi_client = ManagedServiceIdentityClient(self.credentials,
                                                       self.subscription_id)
        self.policy_client = PolicyClient(self.credentials,
                                          self.subscription_id)
        self.authorization_client = AuthorizationManagementClient(
            self.credentials, self.subscription_id)
        self.storage_client = StorageManagementClient(self.credentials,
                                                      self.subscription_id)
        # adls2 storage client
        self.adls2_client = DataLakeServiceClient(
            account_url="{}://{}.dfs.core.windows.net".format(
                "https", self.storage_account_name),
            credential=self.client_secret_credential)
Example #11
0
def main():

    SUBSCRIPTION_ID = os.environ.get("SUBSCRIPTION_ID", None)
    CLIENT_OID = os.environ.get("CLIENT_OID", None)
    GROUP_NAME = "testgroupx"
    ROLE_ASSIGNMENT = "88888888-7000-0000-0000-000000000003"
    ROLE_DEFINITION = "e078ab98-ef3a-4c9a-aba7-12f5172b45d0"
    SCOPE = "subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}".format(
        subscriptionId=SUBSCRIPTION_ID, resourceGroupName=GROUP_NAME)

    # Create client
    # # For other authentication approaches, please see: https://pypi.org/project/azure-identity/
    resource_client = ResourceManagementClient(
        credential=DefaultAzureCredential(), subscription_id=SUBSCRIPTION_ID)
    authorization_client = AuthorizationManagementClient(
        credential=DefaultAzureCredential(),
        subscription_id=SUBSCRIPTION_ID,
        api_version="2018-01-01-preview")

    # Create resource group
    resource_client.resource_groups.create_or_update(GROUP_NAME,
                                                     {"location": "eastus"})

    # Create role assignment
    role_assignment = authorization_client.role_assignments.create(
        SCOPE, ROLE_ASSIGNMENT, {
            "role_definition_id":
            "/subscriptions/" + SUBSCRIPTION_ID +
            "/providers/Microsoft.Authorization/roleDefinitions/" +
            ROLE_DEFINITION,
            "principal_id":
            CLIENT_OID,
        })
    print("Create role assignment:\n{}".format(role_assignment))

    # Get role assignment
    role_assignment = authorization_client.role_assignments.get(
        SCOPE, ROLE_ASSIGNMENT)
    print("Get role assignment:\n{}".format(role_assignment))

    # Delete role assignment
    role_assignment = authorization_client.role_assignments.delete(
        SCOPE, ROLE_ASSIGNMENT)
    print("Delete role assignment.\n")

    # Delete Group
    resource_client.resource_groups.begin_delete(GROUP_NAME).result()
Example #12
0
def add_service_principal_to_role(credentials, subscription_id, spoid):
    auth_client = AuthorizationManagementClient(credentials, subscription_id)
    scope = '/subscriptions/' + subscription_id
    # ARM Reader role is hardcoded here
    role_definition_id = '/subscriptions/' + subscription_id + '/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7'
    principal_id = spoid
    # Try to assign the Service Principal to the Role... but a lot could go wrong.
    try:
        result = auth_client.role_assignments.create(
            scope, uuid.uuid4(),
            RoleAssignmentProperties(role_definition_id, principal_id))
        success = True
    # Tell the user what went wrong.
    except Exception as e:
        result = e
        success = False

    return result, success
Example #13
0
def get_rbac_permissions(context, sub_id):
    print(f"Getting rbac permissions for subscription: {sub_id}")
    auth_client = AuthorizationManagementClient(context.auth.resource_cred,
                                                sub_id)
    rbacs = ["rbac"]

    for role in auth_client.role_assignments.list():
        scope = role.scope
        principal = role.principal_id
        assignment_id = role.id
        role_id = role.role_definition_id
        #role_id = f'/subscriptions/{sub_id}/providers/Microsoft.Authorization/roleAssignments/{role.name}'
        role_type, permissions = _get_permissions(context.auth.resource_cred,
                                                  role_id)
        # querying for assignment id will give type of AADobject
        rbacs += (_map_admin_type(sub_id, assignment_id, principal, scope,
                                  role_id, role_type, permissions))

    print(f"Finished management certs for subscription: {sub_id}")
    return rbacs
Example #14
0
    def setup_client(self, context):
        #user_id = context['environment']['openstack.params']['auth']['credentials']['ADMIN_USER_ID']
        #user_pw= context['environment']['openstack.params']['auth']['credentials']['ADMIN_USER_PW']
        #azure_tenant_id= str(context['environment']['openstack.params']['auth']['AZURE_TENANT_ID'])
        subscription_id = str(context['environment']['openstack.params']
                              ['auth']['SUBSCRIPTION_ID'])
        credentials = UserPassCredentials(
            "*****@*****.**",  # Your new user
            "XXXX",  # Your password
            #user_id,
            #user_pw,
            resource="https://graph.windows.net")
        azure_tenant_id = "cc27778d-9be"
        self.graphrbac_client = GraphRbacManagementClient(
            GraphRbacManagementClientConfiguration(credentials,
                                                   azure_tenant_id))

        #subscription_id = '1beafe45-ce54'
        self.authorization_client = AuthorizationManagementClient(
            AuthorizationManagementClientConfiguration(credentials,
                                                       subscription_id))
Example #15
0
    def assign_keylistrole_appservice(self, resource_group_name, storage_name,
                                      app_service_name):
        resource_provider = "Microsoft.Storage"
        resource_type = "storageAccounts"
        scope = '/subscriptions/%s/resourceGroups/%s/providers/%s/%s/%s' % (
            self.subscription_id, resource_group_name, resource_provider,
            resource_type, storage_name)
        role_assignment_name = str(uuid.uuid4())
        # id for "Storage Account Key Operator Service Role" https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#storage-account-key-operator-service-role
        role_id = "/subscriptions/%s/providers/Microsoft.Authorization/roleDefinitions/%s" % (
            self.subscription_id, "81a9662b-bebf-436f-a333-f67b29880f12")
        principal_id = self.get_object_id(app_service_name)
        props = RoleAssignmentProperties(role_definition_id=role_id,
                                         principal_id=principal_id)

        auth_cli = AuthorizationManagementClient(self.credentials,
                                                 self.subscription_id,
                                                 api_version="2015-07-01")
        resp = auth_cli.role_assignments.create(scope,
                                                role_assignment_name,
                                                properties=props)
        print("%s App Service authorized to access %s Storage account" %
              (app_service_name, storage_name))
        return role_assignment_name
Example #16
0
def run_example():
    """Resource Group management example."""
    #
    # Create the Resource Manager Client with an Application (service principal) token provider
    #
    subscription_id = os.environ.get(
        'AZURE_SUBSCRIPTION_ID',
        '11111111-1111-1111-1111-111111111111')  # your Azure Subscription Id
    credentials = ServicePrincipalCredentials(
        client_id=os.environ['AZURE_CLIENT_ID'],
        secret=os.environ['AZURE_CLIENT_SECRET'],
        tenant=os.environ['AZURE_TENANT_ID'])
    resource_client = ResourceManagementClient(credentials, subscription_id)
    compute_client = ComputeManagementClient(credentials, subscription_id)
    network_client = NetworkManagementClient(credentials, subscription_id)
    authorization_client = AuthorizationManagementClient(
        credentials, subscription_id)

    # Create Resource group
    print('\nCreate Resource Group')
    resource_group = resource_client.resource_groups.create_or_update(
        GROUP_NAME, {'location': LOCATION})
    print_item(resource_group)

    if USER_ASSIGNED_IDENTITY:
        # Create a User Assigned Identity if needed
        print("\nCreate User Assigned Identity")
        msi_client = ManagedServiceIdentityClient(credentials, subscription_id)
        user_assigned_identity = msi_client.user_assigned_identities.create_or_update(
            GROUP_NAME,
            "myMsiIdentity",  # Any name, just a human readable ID
            LOCATION)
        print_item(user_assigned_identity)

    print("\nCreate Network")
    # Create Network components of the VM
    # This is not MSI related and is just required to create the VM
    subnet = create_virtual_network(network_client)
    public_ip = create_public_ip(network_client)
    nic = create_network_interface(network_client, subnet, public_ip)
    print_item(nic)

    params_identity = {}
    if USER_ASSIGNED_IDENTITY and SYSTEM_ASSIGNED_IDENTITY:
        params_identity[
            'type'] = ResourceIdentityType.system_assigned_user_assigned
        params_identity['user_assigned_identities'] = {
            user_assigned_identity.id: {}
        }
    elif USER_ASSIGNED_IDENTITY:  # User Assigned only
        params_identity['type'] = ResourceIdentityType.user_assigned
        params_identity['user_assigned_identities'] = {
            user_assigned_identity.id: {}
        }
    elif SYSTEM_ASSIGNED_IDENTITY:  # System assigned only
        params_identity['type'] = ResourceIdentityType.system_assigned

    # Create a VM MSI enabled
    params_create = {
        'location': LOCATION,
        'os_profile': get_os_profile(),
        'hardware_profile': get_hardware_profile(),
        'network_profile': get_network_profile(nic.id),
        'storage_profile': get_storage_profile(),
        # Activate MSI on that VM
        'identity': params_identity
    }

    print("\nCreate VM")
    vm_poller = compute_client.virtual_machines.create_or_update(
        GROUP_NAME,
        VM_NAME,
        params_create,
    )
    vm_result = vm_poller.result()
    print_item(vm_result)

    # Get the PublicIP after VM creation, since assignment is dynamic
    public_ip = network_client.public_ip_addresses.get(GROUP_NAME,
                                                       PUBLIC_IP_NAME)

    # By default, the MSI accounts have no permissions
    # Next part is assignment of permissions to the account
    # Example is Resource Group access as Contributor, but
    # you can any permissions you need.

    msi_accounts_to_assign = []
    if SYSTEM_ASSIGNED_IDENTITY:
        msi_accounts_to_assign.append(vm_result.identity.principal_id)
    if USER_ASSIGNED_IDENTITY:
        msi_accounts_to_assign.append(user_assigned_identity.principal_id)

    print("\nAssign permissions to MSI identities")

    # Get "Contributor" built-in role as a RoleDefinition object
    role_name = 'Contributor'
    roles = list(
        authorization_client.role_definitions.list(
            resource_group.id, filter="roleName eq '{}'".format(role_name)))
    assert len(roles) == 1
    contributor_role = roles[0]

    # Add RG scope to the MSI identities:
    for msi_identity in msi_accounts_to_assign:

        role_assignment = authorization_client.role_assignments.create(
            resource_group.id,
            uuid.uuid4(),  # Role assignment random name
            {
                'role_definition_id': contributor_role.id,
                'principal_id': msi_identity
            })
        print_item(role_assignment)

    print("You can connect to the VM using:")
    print("ssh {}@{}".format(
        ADMIN_LOGIN,
        public_ip.ip_address,
    ))
    print("And password: {}\n".format(ADMIN_PASSWORD))

    input("Press enter to delete this Resource Group.")

    # Delete Resource group and everything in it
    print('Delete Resource Group')
    delete_async_operation = resource_client.resource_groups.delete(GROUP_NAME)
    delete_async_operation.wait()
    print("\nDeleted: {}".format(GROUP_NAME))
Example #17
0
 def get_client(self, subscription_id: str):
     client = AuthorizationManagementClient(
         self.credentials.get_credentials('arm'),
         subscription_id=subscription_id)
     client._client.config.add_user_agent(get_user_agent())
     return client
import os
from azure.identity import ClientSecretCredential
from azure.mgmt.authorization import AuthorizationManagementClient

subscription_id = '96f7a6ad-39d4-42e5-b676-a510a9e6fd22'
tenant_id = '72f988bf-86f1-41af-91ab-2d7cd011db47'
client_id = 'fd2bfb66-5b4c-492e-8f39-44699600bca8'
client_secret = 'nBQ0.q_i76XQn_318O-sk19.la_UswC-9c'

credential = ClientSecretCredential(tenant_id=tenant_id,
                                    client_id=client_id,
                                    client_secret=client_secret)

authorizationClient = AuthorizationManagementClient(credential,
                                                    subscription_id)
roles = authorizationClient.role_assignments.list()
for role in roles:
    print(role)
Example #19
0
 def AuthorizationManagementClient(self):
     from azure.mgmt.authorization import AuthorizationManagementClient
     return AuthorizationManagementClient(self.ManagementCredentials,
                                          self.subscription_id)
Example #20
0
def get_client_Auth():
    return AuthorizationManagementClient(get_credentials(), setting.SUBSCRIPTION_ID)
Example #21
0
    def _create_azure_state_storage(cls, providers: dict) -> None:
        resource_group_name = providers["terraform"]["backend"]["azurerm"][
            "resource_group_name"]

        region = providers["provider"]["azurerm"]["location"]
        subscription_id = providers["provider"]["azurerm"]["subscription_id"]
        storage_account_name = providers["terraform"]["backend"]["azurerm"][
            "storage_account_name"]
        container_name = providers["terraform"]["backend"]["azurerm"][
            "container_name"]

        # Create RG
        credential = Azure.get_credentials()
        resource_client = ResourceManagementClient(credential, subscription_id)
        try:
            rg_result = resource_client.resource_groups.create_or_update(
                resource_group_name, {"location": region})
        except ResourceNotFoundError as e:
            if "SubscriptionNotFound" in e.message:
                raise UserErrors(
                    f"SubscriptionId {subscription_id} does not exists. Please check and use the correct Subscription Id. "
                    "This is used for accessing the resources in the Resource Group."
                )
        except HttpResponseError as e:
            if "InvalidSubscriptionId" in e.message:
                raise UserErrors(
                    f"Malformed or Invalid SubscriptionId {subscription_id} used. Please check and use the correct Subscription Id. "
                    "This is used for accessing the resources in the Resource Group."
                )

        logger.debug(
            f"Provisioned resource group {rg_result.name} in the {rg_result.location} region"
        )
        authorization_client = AuthorizationManagementClient(
            credential, subscription_id, api_version="2018-01-01-preview")

        owner_role_name = "Owner"
        owner_role = list(
            authorization_client.role_definitions.list(
                rg_result.id,
                filter="roleName eq '{}'".format(owner_role_name)))[0]

        storage_role_name = "Storage Blob Data Owner"
        storage_role = list(
            authorization_client.role_definitions.list(
                rg_result.id,
                filter="roleName eq '{}'".format(storage_role_name)))[0]

        key_vault_role_name = "Key Vault Administrator"
        key_vault_role = list(
            authorization_client.role_definitions.list(
                rg_result.id,
                filter="roleName eq '{}'".format(key_vault_role_name)))[0]

        role_assignments = authorization_client.role_assignments.list_for_resource_group(
            rg_result.name)
        for role_assignment in role_assignments:
            if role_assignment.role_definition_id == owner_role.id:
                try:
                    authorization_client.role_assignments.create(
                        scope=
                        f"/subscriptions/{subscription_id}/resourceGroups/{rg_result.name}",
                        role_assignment_name=uuid4(),
                        parameters={
                            "role_definition_id": storage_role.id,
                            "principal_id": role_assignment.principal_id,
                        },
                    )
                except ResourceExistsError:
                    pass
                try:
                    authorization_client.role_assignments.create(
                        scope=
                        f"/subscriptions/{subscription_id}/resourceGroups/{rg_result.name}",
                        role_assignment_name=uuid4(),
                        parameters={
                            "role_definition_id": key_vault_role.id,
                            "principal_id": role_assignment.principal_id,
                        },
                    )
                except ResourceExistsError:
                    pass

        # Create SA
        storage_client = StorageManagementClient(credential, subscription_id)
        try:
            storage_client.storage_accounts.get_properties(
                resource_group_name, storage_account_name)
            logger.debug(
                f"Storage account {storage_account_name} already exists!")
        except ResourceNotFoundError:
            logger.debug("Need to create storage account")
            # create sa
            try:
                poller = storage_client.storage_accounts.begin_create(
                    resource_group_name,
                    storage_account_name,
                    {
                        "location": region,
                        "kind": "StorageV2",
                        "sku": {
                            "name": "Standard_LRS"
                        },
                    },
                )
            except ResourceExistsError:
                raise UserErrors(
                    "The Storage Account name already exists in Another Subscription. "
                    "Please change the Name or Org Name in Config.")

            account_result = poller.result()
            logger.debug(f"Provisioned storage account {account_result.name}")
            # TODO(ankur): assign Storage Blob Data Contributor to this SA,
            # otherwise it doesn't work

        # create container
        try:
            container = storage_client.blob_containers.get(
                resource_group_name, storage_account_name, container_name)
            logger.debug(f"container {container.name} exists")
        except ResourceNotFoundError:
            logger.debug("Need to create container")
            container = storage_client.blob_containers.create(
                resource_group_name, storage_account_name, container_name, {})
            logger.debug(f"Provisioned container {container.name}")
    def stop(self, data):
        credentials, _, _ = self._get_credentials()

        # Do NOT use the conf but the actual values from the cluster here
        cluster_resource_id = data["cluster"]["id"]
        _, _, subscription_id, _, resource_group, _, _, _, cluster_name = cluster_resource_id.split(
            "/")
        clusters_client = ContainerServiceClient(credentials, subscription_id)

        # Try to detach from ACR if required. It is not mandatory but if not done, it would pollute
        # the ACR with multiple invalid role attachments and consume attachment quotas
        node_resource_group = data["cluster"]["node_resource_group"]
        acr_attachment = data.get("acr_attachment", None)
        if not _is_none_or_blank(acr_attachment):
            logging.info(
                "Cluster has an ACR attachment, check managed identity")
            cluster_identity_profile = data["cluster"]["identity_profile"]
            kubelet_mi_resource_id = cluster_identity_profile[
                "kubeletidentity"].get("resource_id", None)
            if kubelet_mi_resource_id is not None:
                _, _, mi_subscription_id, _, mi_resource_group, _, _, _, mi_name = kubelet_mi_resource_id.split(
                    "/")
                if mi_resource_group == node_resource_group:
                    logging.info(
                        "Cluster has an AKS managed kubelet identity, try to detach"
                    )
                    authorization_client = AuthorizationManagementClient(
                        credentials, acr_attachment["subscription_id"])
                    try:
                        authorization_client.role_assignments.delete_by_id(
                            acr_attachment["role_assignment"]["id"])
                    except ResourceNotFoundError as e:
                        logging.warn(
                            "It looks that the ACR role assignment doesnt exist. Ignore this step"
                        )

        # Detach Vnet like ACR
        vnet_attachment = data.get("vnet_attachment", None)
        if not _is_none_or_blank(vnet_attachment):
            logging.info(
                "Cluster has an Vnet attachment, check managed identity")
            if "role_assignment" in vnet_attachment:
                logging.info(
                    "Cluster has an AKS managed kubelet identity, try to detach"
                )
                authorization_client = AuthorizationManagementClient(
                    credentials, vnet_attachment["subscription_id"])
                try:
                    authorization_client.role_assignments.delete_by_id(
                        vnet_attachment["role_assignment"]["id"])
                except ResourceNotFoundError as e:
                    logging.warn(
                        "It looks that the Vnet role assignment doesnt exist. Ignore this step"
                    )

        def do_delete():
            future = clusters_client.managed_clusters.begin_delete(
                resource_group, cluster_name)
            return future.result()

        delete_result = run_and_process_cloud_error(do_delete)

        # delete returns void, so we poll until the cluster is really gone
        gone = False
        while not gone:
            time.sleep(5)
            try:
                cluster = clusters_client.managed_clusters.get(
                    resource_group, cluster_name)
                if cluster.provisioning_state.lower() != 'deleting':
                    logging.info(
                        "Cluster is not deleting anymore, must be deleted now (state = %s)"
                        % cluster.provisioning_state)
            # other exceptions should not be ignored
            except ResourceNotFoundError as e:
                logging.info(
                    "Cluster doesn't seem to exist anymore, considering it deleted"
                )
                gone = True
    def start(self):
        """
        Build the create cluster request.
        """
        credentials, subscription_id, managed_identity_id = self._get_credentials(
        )

        # Fetch metadata about the instance
        metadata = get_instance_metadata()

        # Resource group
        resource_group = self.config.get('resourceGroup', None)
        dss_host_resource_group = metadata["compute"]["resourceGroupName"]
        if _is_none_or_blank(resource_group):
            resource_group = dss_host_resource_group
            logging.info(
                "Using same resource group as DSS: {}".format(resource_group))

        # Location
        location = self.config.get('location', None)
        if _is_none_or_blank(location):
            location = metadata["compute"]["location"]
            logging.info("Using same location as DSS: {}".format(location))

        # Consistency checks
        if _is_none_or_blank(resource_group):
            raise Exception(
                "A resource group to put the cluster in is required")
        if _is_none_or_blank(location):
            raise Exception("A location to put the cluster in is required")

        # AKS Client
        clusters_client = None

        # Credit the cluster to DATAIKU
        if os.environ.get("DISABLE_AZURE_USAGE_ATTRIBUTION", "0") == "1":
            logging.info("Azure usage attribution is disabled")
            clusters_client = ContainerServiceClient(credentials,
                                                     subscription_id)
        else:
            policy = UserAgentPolicy()
            policy.add_user_agent('pid-fd3813c7-273c-5eec-9221-77323f62a148')
            clusters_client = ContainerServiceClient(credentials,
                                                     subscription_id,
                                                     user_agent_policy=policy)

        # check that the cluster doesn't exist yet, otherwise azure will try to update it
        # and will almost always fail
        try:
            existing = clusters_client.managed_clusters.get(
                resource_group, self.cluster_name)
            if existing is not None:
                raise Exception(
                    "A cluster with name %s in resource group %s already exists"
                    % (self.cluster_name, resource_group))
        except CloudError as e:
            logging.info("Cluster doesn't seem to exist yet")
        except ResourceNotFoundError as e:
            logging.info("Cluster doesn't seem to exist yet")

        cluster_builder = ClusterBuilder(clusters_client)
        cluster_builder.with_name(self.cluster_name)
        cluster_builder.with_dns_prefix("{}-dns".format(self.cluster_name))
        cluster_builder.with_resource_group(resource_group)
        cluster_builder.with_location(location)
        cluster_builder.add_tags(self.config.get("tags", None))
        cluster_builder.with_linux_profile()  # default is None
        cluster_builder.with_network_profile(
            service_cidr=self.config.get("serviceCIDR", None),
            dns_service_ip=self.config.get("dnsServiceIP", None),
            load_balancer_sku=self.config.get("loadBalancerSku", None),
            outbound_type=self.config.get("outboundType", None),
            network_plugin=self.config.get("networkPlugin"),
            docker_bridge_cidr=self.config.get("dockerBridgeCidr"))

        if self.config.get("useCustomNodeResourceGroup", False):
            cluster_builder.with_node_resource_group(
                self.config.get("nodeResourceGroup"))

        # Cluster identity
        connection_info = self.config.get("connectionInfo", None)
        cluster_idendity_legacy_use_distinct_sp = self.config.get(
            "useDistinctSPForCluster", False)
        cluster_idendity_legacy_sp = self.config.get("clusterServicePrincipal",
                                                     None)
        cluster_identity_type = None
        cluster_identity = None
        if not _is_none_or_blank(
                connection_info) or cluster_idendity_legacy_use_distinct_sp:
            logging.warn(
                "Using legacy options to configure cluster identity. Clear them to use the new ones."
            )
            if not cluster_idendity_legacy_use_distinct_sp and not _is_none_or_blank(
                    connection_info):
                cluster_sp = connection_info
            elif cluster_idendity_legacy_use_distinct_sp and not _is_none_or_blank(
                    cluster_idendity_legacy_sp):
                cluster_sp = self.config.get("clusterServicePrincipal")
            else:
                raise Exception(
                    "Legacy options are not complete enough to determine cluster identity settings"
                )
            cluster_builder.with_cluster_sp_legacy(
                cluster_service_principal_connection_info=cluster_sp)
        else:
            cluster_identity = self.config.get(
                "clusterIdentity", {"identityType": "managed-identity"})
            cluster_identity_type = cluster_identity.get(
                "identityType", "managed-identity")
            if cluster_identity_type == "managed-identity":
                if cluster_identity.get("inheritDSSIdentity", True):
                    logging.info(
                        "Need to inspect Managed Identity infos from Azure")
                    if metadata is None:
                        metadata = get_instance_metadata()
                    vm_resource_group = metadata["compute"][
                        "resourceGroupName"]
                    vm_name = metadata["compute"]["name"]
                    compute_client = ComputeManagementClient(
                        credentials, subscription_id)
                    vm = compute_client.virtual_machines.get(
                        vm_resource_group, vm_name)
                    # No choice here but to use the first one
                    if managed_identity_id is None:
                        managed_identity_id = next(
                            iter(vm.identity.user_assigned_identities.keys()))
                    for managed_identity_resource_id, managed_identity_properties in vm.identity.user_assigned_identities.items(
                    ):
                        if managed_identity_id == managed_identity_resource_id or managed_identity_id == managed_identity_properties.client_id:
                            break
                    logging.info("Found managed identity id {}".format(
                        managed_identity_resource_id))
                    cluster_builder.with_managed_identity(
                        managed_identity_resource_id)
                    cluster_builder.with_kubelet_identity(
                        managed_identity_resource_id,
                        managed_identity_properties.client_id,
                        managed_identity_properties.principal_id)
                else:
                    control_plane_mi = None if cluster_identity.get(
                        "useAKSManagedIdentity", True
                    ) else cluster_identity["controlPlaneUserAssignedIdentity"]
                    cluster_builder.with_managed_identity(control_plane_mi)
                    if control_plane_mi is None:
                        logging.info(
                            "Configure cluster with system managed identity.")
                    else:
                        logging.info(
                            "Configure cluster with user assigned identity: {}"
                            .format(control_plane_mi))
                    if not cluster_identity.get("useAKSManagedKubeletIdentity",
                                                True):
                        kubelet_mi = cluster_identity[
                            "kubeletUserAssignedIdentity"]
                        _, _, mi_subscription_id, _, mi_resource_group, _, _, _, mi_name = kubelet_mi.split(
                            "/")
                        msiclient = ManagedServiceIdentityClient(
                            AzureIdentityCredentialAdapter(credentials),
                            mi_subscription_id)
                        mi = msiclient.user_assigned_identities.get(
                            mi_resource_group, mi_name)
                        cluster_builder.with_kubelet_identity(
                            kubelet_mi, mi.client_id, mi.principal_id)
                        logging.info(
                            "Configure kubelet identity with user assigned identity resourceId=\"{}\", clientId=\"{}\", objectId=\"{}\""
                            .format(kubelet_mi, mi.client_id, mi.principal_id))
            elif cluster_identity_type == "service-principal":
                cluster_builder.with_cluster_sp(cluster_identity["clientId"],
                                                cluster_identity["password"])
                logging.info("Configure cluster with service principal")
            else:
                raise Exception(
                    "Cluster identity type \"{}\" is unknown".format(
                        cluster_identity_type))

        # Fail fast for non existing ACRs to avoid drama in case of failure AFTER cluster is created
        acr_role_id = None
        authorization_client = None
        if cluster_identity_type is not None and cluster_identity is not None:
            if cluster_identity_type == "managed-identity" and cluster_identity.get(
                    "useAKSManagedKubeletIdentity",
                    True) and not cluster_identity.get("inheritDSSIdentity",
                                                       True):
                acr_name = cluster_identity.get("attachToACRName", None)
                if not _is_none_or_blank(acr_name):
                    # build acr scope
                    acr_identifier_splitted = acr_name.split('/')
                    acr_subscription_id = subscription_id
                    acr_resource_group = resource_group
                    if 9 == len(acr_identifier_splitted):
                        _, _, acr_subscription_id, _, acr_resource_group, _, _, _, acr_name = acr_identifier_splitted
                    elif 2 == len(acr_identifier_splitted):
                        acr_resource_group, acr_name = acr_identifier_splitted

                    authorization_client = AuthorizationManagementClient(
                        credentials, acr_subscription_id)
                    acr_scope = "/subscriptions/{acr_subscription_id}/resourceGroups/{acr_resource_group}/providers/Microsoft.ContainerRegistry/registries/{acr_name}".format(
                        **locals())
                    try:
                        acr_roles = list(
                            authorization_client.role_definitions.list(
                                acr_scope, "roleName eq 'AcrPull'"))
                    except ResourceNotFoundError as e:
                        raise Exception(
                            "ACR {} not found. Check it exists and you are Owner of it."
                            .format(acr_scope))
                    if 0 == len(acr_roles):
                        raise Exception(
                            "Could not find the AcrPull role on the ACR {}. Check you are Owner of it."
                            .format(acr_scope))
                    else:
                        acr_role_id = acr_roles[0].id
                        logging.info("ACR pull role id: %s", acr_role_id)

                    # Try to run a fake role assignment. Depending on the failure type we know if we are Owner or not
                    try:
                        fake_role_assignment = authorization_client.role_assignments.create(
                            scope=acr_scope,
                            role_assignment_name=str(uuid.uuid4()),
                            parameters={
                                "properties": {
                                    "role_definition_id":
                                    acr_role_id,
                                    "principal_id":
                                    "00000000-0000-0000-0000-000000000000",
                                },
                            },
                        )
                    except HttpResponseError as e:
                        if e.reason == "Forbidden" and "AuthorizationFailed" in str(
                                e.error):
                            raise Exception(
                                "Cannot create role assignments on ACR {}. Check that your are Owner of it or provide an existing Kubelet identity."
                                .format(acr_scope))
                        elif e.reason == "Bad Request" and "PrincipalNotFound" in str(
                                e.error):
                            logging.info(
                                "Fake role assignment on ACR looks ok. Identity should be allowed to assign roles in further steps."
                            )
                        else:
                            raise (e)
                    except Exception as e:
                        raise (e)

        # Sanity check for node pools
        node_pool_vnets = set()
        for idx, node_pool_conf in enumerate(self.config.get("nodePools", [])):
            node_pool_builder = cluster_builder.get_node_pool_builder()
            nodepool_vnet = node_pool_conf.get("vnet", None)
            nodepool_subnet = node_pool_conf.get("subnet", None)
            vnet, _ = node_pool_builder.resolve_network(
                inherit_from_host=node_pool_conf.get(
                    "useSameNetworkAsDSSHost"),
                cluster_vnet=nodepool_vnet,
                cluster_subnet=nodepool_subnet,
                connection_info=connection_info,
                credentials=credentials,
                resource_group=resource_group,
                dss_host_resource_group=dss_host_resource_group)
            node_pool_vnets.add(vnet)

        if 1 < len(node_pool_vnets):
            raise Exception(
                "Node pools must all share the same vnet. Current node pools configuration yields vnets {}."
                .format(",".join(node_pool_vnets)))
        elif 0 == len(node_pool_vnets):
            raise Exception(
                "You cannot deploy a cluster without any node pool.")

        # Check role assignments for vnet like on ACR for fail fast if not doable
        vnet_id = node_pool_vnets.pop()
        if not vnet_id.startswith("/"):
            vnet_name = vnet_id
            vnet_id = "/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Network/virtualNetworks/{vnet_name}".format(
                **locals())
        vnet_role_id = None
        if cluster_identity_type is not None and cluster_identity is not None:
            if cluster_identity_type == "managed-identity" and cluster_identity.get(
                    "useAKSManagedIdentity",
                    True) and not cluster_identity.get("inheritDSSIdentity",
                                                       True):
                authorization_client = AuthorizationManagementClient(
                    credentials, subscription_id)
                try:
                    vnet_roles = list(
                        authorization_client.role_definitions.list(
                            vnet_id, "roleName eq 'Contributor'"))
                except ResourceNotFoundError as e:
                    raise Exception(
                        "Vnet {} not found. Check it exists and you are Owner of it."
                        .format(vnet_id))
                if 0 == len(acr_roles):
                    raise Exception(
                        "Could not find the Contributor role on the vnet {}. Check you are Owner of it."
                        .format(vnet_id))
                else:
                    vnet_role_id = vnet_roles[0].id
                    logging.info("Vnet contributor role id: %s", acr_role_id)
                    # Try to run a fake role assignment. Depending on the failure type we know if we are Owner or not
                    try:
                        fake_role_assignment = authorization_client.role_assignments.create(
                            scope=vnet_id,
                            role_assignment_name=str(uuid.uuid4()),
                            parameters={
                                "properties": {
                                    "role_definition_id":
                                    vnet_role_id,
                                    "principal_id":
                                    "00000000-0000-0000-0000-000000000000",
                                },
                            },
                        )
                    except HttpResponseError as e:
                        if e.reason == "Forbidden" and "AuthorizationFailed" in str(
                                e.error):
                            raise Exception(
                                "Cannot create role assignments on Vnet {}. Check that your are Owner of it or provide an existing Controle Plane identity."
                                .format(vnet_id))
                        elif e.reason == "Bad Request" and "PrincipalNotFound" in str(
                                e.error):
                            logging.info(
                                "Fake role assignment on Vnet looks ok. Identity should be allowed to assign roles in further steps."
                            )
                        else:
                            raise (e)
                    except Exception as e:
                        raise (e)

        # Access level
        if self.config.get("privateAccess"):
            cluster_builder.with_private_access(
                self.config.get("privateAccess"))

        cluster_builder.with_cluster_version(
            self.config.get("clusterVersion", None))

        # Node pools
        for idx, node_pool_conf in enumerate(self.config.get("nodePools", [])):
            node_pool_builder = cluster_builder.get_node_pool_builder()
            node_pool_builder.with_idx(idx)
            node_pool_builder.with_vm_size(node_pool_conf.get("vmSize", None))
            vnet = node_pool_conf.get("vnet", None)
            subnet = node_pool_conf.get("subnet", None)
            node_pool_builder.with_network(
                inherit_from_host=node_pool_conf.get(
                    "useSameNetworkAsDSSHost"),
                cluster_vnet=vnet,
                cluster_subnet=subnet,
                connection_info=connection_info,
                credentials=credentials,
                resource_group=resource_group,
                dss_host_resource_group=dss_host_resource_group)

            node_pool_builder.with_availability_zones(
                use_availability_zones=node_pool_conf.get(
                    "useAvailabilityZones", True))

            node_pool_builder.with_node_count(
                enable_autoscaling=node_pool_conf.get("autoScaling", False),
                num_nodes=node_pool_conf.get("numNodes", None),
                min_num_nodes=node_pool_conf.get("minNumNodes", None),
                max_num_nodes=node_pool_conf.get("maxNumNodes", None))

            node_pool_builder.with_mode(
                mode=node_pool_conf.get("mode", "Automatic"),
                system_pods_only=node_pool_conf.get("systemPodsOnly", True))

            node_pool_builder.with_disk_size_gb(
                disk_size_gb=node_pool_conf.get("osDiskSizeGb", 0))
            node_pool_builder.with_node_labels(
                node_pool_conf.get("labels", None))
            node_pool_builder.with_node_taints(
                node_pool_conf.get("taints", None))
            node_pool_builder.add_tags(self.config.get("tags", None))
            node_pool_builder.add_tags(node_pool_conf.get("tags", None))
            node_pool_builder.build()
            cluster_builder.with_node_pool(
                node_pool=node_pool_builder.agent_pool_profile)

        # Run creation
        logging.info("Start creation of cluster")

        def do_creation():
            cluster_create_op = cluster_builder.build()
            return cluster_create_op.result()

        create_result = run_and_process_cloud_error(do_creation)
        logging.info("Cluster creation finished")

        # Attach to ACR
        acr_attachment = {}
        if cluster_identity_type is not None and cluster_identity is not None:
            if cluster_identity_type == "managed-identity" and cluster_identity.get(
                    "useAKSManagedKubeletIdentity",
                    True) and not cluster_identity.get("inheritDSSIdentity",
                                                       True):
                kubelet_mi_object_id = create_result.identity_profile.get(
                    "kubeletidentity").object_id
                logging.info("Kubelet Managed Identity object id: %s",
                             kubelet_mi_object_id)
                if not _is_none_or_blank(acr_role_id):
                    logging.info("Assign ACR pull role id %s to %s",
                                 acr_role_id, kubelet_mi_object_id)
                    role_assignment = authorization_client.role_assignments.create(
                        scope=acr_scope,
                        role_assignment_name=str(uuid.uuid4()),
                        parameters={
                            "properties": {
                                "role_definition_id": acr_role_id,
                                "principal_id": kubelet_mi_object_id,
                            },
                        },
                    )
                    acr_attachment.update({
                        "name":
                        acr_name,
                        "resource_group":
                        acr_resource_group,
                        "subscription_id":
                        acr_subscription_id,
                        "resource_id":
                        acr_scope,
                        "role_assignment":
                        role_assignment.as_dict(),
                    })

        # Attach to VNET to allow LoadBalancers creation
        vnet_attachment = {}
        if cluster_identity_type is not None and cluster_identity is not None:
            if cluster_identity_type == "managed-identity" and cluster_identity.get(
                    "useAKSManagedIdentity",
                    True) and not cluster_identity.get("inheritDSSIdentity",
                                                       True):
                # And here we are blocked because we cant get the principal id of a System Assigned Managed Id easily
                control_plane_object_id = create_result.identity.principal_id
                logging.info("Controle Plane Managed Identity object id: %s",
                             control_plane_object_id)
                if not _is_none_or_blank(vnet_role_id):
                    logging.info("Assign Vnet contributolr role id %s to %s",
                                 vnet_role_id, control_plane_object_id)
                    vnet_role_assignment = authorization_client.role_assignments.create(
                        scope=vnet_id,
                        role_assignment_name=str(uuid.uuid4()),
                        parameters={
                            "properties": {
                                "role_definition_id": vnet_role_id,
                                "principal_id": control_plane_object_id,
                            },
                        },
                    )
                    vnet_attachment.update({
                        "subscription_id":
                        subscription_id,
                        "resource_id":
                        vnet_id,
                        "role_assignment":
                        vnet_role_assignment.as_dict(),
                    })

        logging.info("Fetching kubeconfig for cluster {} in {}...".format(
            self.cluster_name, resource_group))

        def do_fetch():
            return clusters_client.managed_clusters.list_cluster_admin_credentials(
                resource_group, self.cluster_name)

        get_credentials_result = run_and_process_cloud_error(do_fetch)
        kube_config_content = get_credentials_result.kubeconfigs[
            0].value.decode("utf8")
        logging.info("Writing kubeconfig file...")
        kube_config_path = os.path.join(os.getcwd(), "kube_config")
        with open(kube_config_path, 'w') as f:
            f.write(kube_config_content)

        overrides = make_overrides(
            self.config,
            yaml.safe_load(kube_config_content),
            kube_config_path,
            acr_name=None
            if _is_none_or_blank(acr_attachment) else acr_attachment["name"],
        )

        return [
            overrides, {
                "kube_config_path": kube_config_path,
                "cluster": create_result.as_dict(),
                "acr_attachment": acr_attachment,
                "vnet_attachment": vnet_attachment
            }
        ]
Example #24
0
 def get_client(self, subscription_id: str):
     return AuthorizationManagementClient(
         self.credentials.get_credentials('arm'),
         subscription_id=subscription_id)
Example #25
0
from azure.mgmt.resource import ResourceManagementClient

from azure.mgmt.authorization import AuthorizationManagementClient

subscription_id = ''
scope = ''
role_assignment_name = '199d4427-8709-4d93-a15b-61d377708ae6'
role_assignment_id = '' + '199d4427-8709-4d93-a15b-61d377708ae6'
role_definition_id = ''
principal_id = ''

if __name__ == "__main__":
    authorization_client = get_client_from_cli_profile(
        AuthorizationManagementClient)  # , subscription_id=subscription_id )
    authorization_models = AuthorizationManagementClient.models(
        '2018-09-01-preview')

    parameters = authorization_models.RoleAssignmentCreateParameters(
        role_definition_id=role_definition_id,
        principal_id=principal_id,
        principal_type='User',
        can_delegate=None)

    # role_list = authorization_client.role_assignments.list(filter=None, custom_headers=None, raw=False)

    print('########################################################')

    # for role_assignment in role_list:
    #     print('id: {}'.format(role_assignment.id))
    #     print('name: {}'.format(role_assignment.name))
    #     print('principal_id: {}'.format(role_assignment.principal_id))
Example #26
0
    def create_instance(self, metadata, verbose=False):
        from azure.common.credentials import ServicePrincipalCredentials
        from azure.mgmt.resource import ResourceManagementClient
        from azure.mgmt.compute import ComputeManagementClient
        from azure.mgmt.network import NetworkManagementClient
        from azure.mgmt.compute.models import DiskCreateOption
        from azure.mgmt.authorization import AuthorizationManagementClient

        # TODO: Remove this guard after Azure fixes the issue
        if self.preemptible:
            print(
                "Spot instances are not functional on our subscription just yet. Azure is currently investigating this issue."
            )
            print("This guard will be removed as soon as the issue is fixed.")
            exit(1)

        azure_resource_group = self.azure_resource_group_base + uuid.uuid4(
        ).hex[:6]
        region = metadata['region']
        instance_type_str = 'a spot instance' if self.preemptible else 'an instance'
        print('Creating {} of type {} in {}'.format(instance_type_str,
                                                    self.instance_type,
                                                    region))

        credentials = ServicePrincipalCredentials(
            client_id=self.azure_client_id,
            secret=self.azure_authentication_key,
            tenant=self.azure_tenant_id,
        )
        resource_group_client = ResourceManagementClient(
            credentials, self.subscription_id)
        network_client = NetworkManagementClient(credentials,
                                                 self.subscription_id)
        compute_client = ComputeManagementClient(credentials,
                                                 self.subscription_id)
        authorization_client = AuthorizationManagementClient(
            credentials,
            self.subscription_id,
        )
        resource_group_params = {
            'location': region,
            'tags': self.tags,
        }
        resource_group = resource_group_client.resource_groups.create_or_update(
            azure_resource_group, resource_group_params)
        vm_name = 'doodad-vm'
        print('VM name:', vm_name)
        print('resource group id:', resource_group.id)

        public_ip_addess_params = {
            'location': region,
            'public_ip_allocation_method': 'Dynamic'
        }
        try:
            poller = network_client.public_ip_addresses.create_or_update(
                azure_resource_group, 'myIPAddress', public_ip_addess_params)
            publicIPAddress = poller.result()

            vnet_params = {
                'location': region,
                'address_space': {
                    'address_prefixes': ['10.0.0.0/16']
                }
            }
            network_client.virtual_networks.create_or_update(
                azure_resource_group, 'myVNet', vnet_params)
            subnet_params = {'address_prefix': '10.0.0.0/24'}
            poller = network_client.subnets.create_or_update(
                azure_resource_group, 'myVNet', 'mySubnet', subnet_params)
            subnet_info = poller.result()
            nic_params = {
                'location':
                region,
                'ip_configurations': [{
                    'name': 'myIPConfig',
                    'public_ip_address': publicIPAddress,
                    'subnet': {
                        'id': subnet_info.id
                    }
                }]
            }
            poller = network_client.network_interfaces.create_or_update(
                azure_resource_group, 'myNic', nic_params)
            nic = poller.result()

            startup_script_str = metadata['startup_script']
            # TODO: how do we use this shutdown script?
            shutdown_script_str = metadata['shutdown_script']
            for old, new in [
                ('DOODAD_LOG_PATH', self.log_path),
                ('DOODAD_STORAGE_ACCOUNT_NAME',
                 self.connection_info['AccountName']),
                ('DOODAD_STORAGE_ACCOUNT_KEY',
                 self.connection_info['AccountKey']),
                ('DOODAD_CONTAINER_NAME', self.azure_container),
                ('DOODAD_REMOTE_SCRIPT_PATH', metadata['remote_script_path']),
                ('DOODAD_REMOTE_SCRIPT_ARGS', metadata['remote_script_args']),
                ('DOODAD_SHELL_INTERPRETER', metadata['shell_interpreter']),
                ('DOODAD_TERMINATE_ON_END', metadata['terminate']),
                ('DOODAD_OVERWRITE_LOGS', metadata['overwrite_logs']),
                ('DOODAD_INSTALL_NVIDIA_EXTENSION',
                 metadata['install_nvidia_extension'])
            ]:
                startup_script_str = startup_script_str.replace(old, new)
            custom_data = b64e(startup_script_str)

            # vm_name = ('doodad'+str(uuid.uuid4()).replace('-', ''))[:15]
            # this authenthication code is based on
            # https://docs.microsoft.com/en-us/samples/azure-samples/compute-python-msi-vm/compute-python-msi-vm/
            from azure.mgmt.compute import models
            params_identity = {
                'type': models.ResourceIdentityType.system_assigned,
            }
            vm_parameters = {
                'location': region,
                'os_profile': {
                    'computer_name': vm_name,
                    'admin_username': '******',
                    'admin_password': '******',
                    'custom_data': custom_data,
                },
                'hardware_profile': {
                    'vm_size': self.instance_type
                },
                'storage_profile': {
                    'image_reference': {
                        "offer": "UbuntuServer",
                        "publisher": "Canonical",
                        "sku": "18.04-LTS",
                        "urn": "Canonical:UbuntuServer:18.04-LTS:latest",
                        "urnAlias": "UbuntuLTS",
                        "version": "latest"
                    }
                },
                'network_profile': {
                    'network_interfaces': [{
                        'id': nic.id
                    }]
                },
                'tags': self.tags,
                'identity': params_identity,
            }
            if metadata['use_data_science_image']:
                vm_parameters['storage_profile']['image_reference'] = {
                    "offer": "ubuntu-1804",
                    "publisher": "microsoft-dsvm",
                    "sku": "1804",
                    "urn": "microsoft-dsvm:ubuntu-1804:1804:latest",
                    "version": "latest"
                }
            if self.preemptible:
                spot_args = {
                    "priority": "Spot",
                    "evictionPolicy": "Deallocate",
                    "billingProfile": {
                        "maxPrice": self.spot_max_price
                    }
                }
                vm_parameters.update(spot_args)
            vm_poller = compute_client.virtual_machines.create_or_update(
                resource_group_name=azure_resource_group,
                vm_name=vm_name,
                parameters=vm_parameters,
            )
            vm_result = vm_poller.result()

            # We need to ensure that the VM has permissions to delete its own
            # resource group. We'll assign the built-in "Contributor" role and limit
            # its scope to this resource group.
            role_name = 'Contributor'
            roles = list(
                authorization_client.role_definitions.list(
                    resource_group.id,
                    filter="roleName eq '{}'".format(role_name)))
            assert len(roles) == 1
            contributor_role = roles[0]

            # Add RG scope to the MSI tokenddd
            for msi_identity in [vm_result.identity.principal_id]:
                authorization_client.role_assignments.create(
                    resource_group.id,
                    uuid.uuid4(),  # Role assignment random name
                    {
                        'role_definition_id': contributor_role.id,
                        'principal_id': msi_identity
                    })
        except (Exception, KeyboardInterrupt) as e:
            if 'resource_group' in locals():
                if verbose:
                    print("Deleting created resource group id: {}.".format(
                        resource_group.id))
                resource_group_client.resource_groups.delete(
                    azure_resource_group)
            from msrestazure.azure_exceptions import CloudError as AzureCloudError
            if isinstance(e, AzureCloudError):
                print("Error when creating VM. Error message:")
                print(e.message + '\n')
                return False, e
            raise e
        success = True
        return success, resource_group.id
Example #27
0
            secret = os.getenv('AZURE_CLIENT_SECRET'),
            tenant = os.getenv('AZURE_TENANT_ID'))
        return credentials
    except TypeError:
        print('\nERROR: Kindly Export the below Environmental vairables to continue ..')
        print('\nAZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID & AZURE_SUBSCRIPTION_ID')
        sys.exit(1)
    

credentials = get_credential()

compute_client = ComputeManagementClient(credentials,subscriptionId)
network_client = NetworkManagementClient(credentials,subscriptionId)
storage_client = StorageManagementClient(credentials,subscriptionId)
resource_client = ResourceManagementClient(credentials, subscriptionId)
auth_client = AuthorizationManagementClient(credentials, subscriptionId)
kv_client = KeyVaultManagementClient(credentials,subscriptionId)
funcapp_client = WebSiteManagementClient(credentials,subscriptionId)


def banner():
    size = int(os.popen('tput cols').read().strip())
    print('\n')
    print('#' * size)
    #print(comment.center(size))
    #print('#' * size,'\n')

def run_script(script_location):
    #args = shlex.split(command)
    output = subprocess.call([script_location])
    return output
Example #28
0
 def getAuthorizationManagementClient(self, subscriptionId):
     return AuthorizationManagementClient(self.__credentialsProvider.getManagementCredentials(), subscriptionId)
Example #29
0
    def add_storage_account(self):
        """
        Creates a storage account then adds the storage account to the vault to manage its keys.
        """
        from azure.mgmt.storage import StorageManagementClient
        from azure.mgmt.storage.models import StorageAccountCreateParameters, Sku, SkuName, Kind
        from msrestazure.azure_active_directory import AADTokenCredentials
        from azure.mgmt.authorization.models import RoleAssignmentCreateParameters
        from azure.keyvault.models import StorageAccountAttributes
        from azure.mgmt.authorization import AuthorizationManagementClient

        self.config.storage_account_name = get_name('sa', '')

        # only user accounts with access to the storage account keys can add a storage account to
        # a vault.  For this reason this sample creates the storage account with a user account
        # authenticated through device login rather than the service principal credentials used
        # in other samples.
        # create the StorageManagementClient with user token credentials
        user_token_creds = AADTokenCredentials(
            self.get_user_token('https://management.core.windows.net/'))

        print('creating storage account %s' % self.config.storage_account_name)
        storage_mgmt_client = StorageManagementClient(
            user_token_creds, self.config.subscription_id)

        # create the storage account
        sa_params = StorageAccountCreateParameters(
            sku=Sku(SkuName.standard_ragrs),
            kind=Kind.storage,
            location=self.config.location)
        sa = storage_mgmt_client.storage_accounts.create(
            resource_group_name=self.config.group_name,
            account_name=self.config.storage_account_name,
            parameters=sa_params).result()

        # the KeyVault service must be given the "Storage Account Key Operator Service Role" on the
        # storage account before the storage account can be added to the vault

        print(
            'granting Azure Key Vault the "Storage Account Key Operator Service Role" on the storage account'
        )
        # find the role definition for "Storage Account Key Operator Service Role"
        filter_str = 'roleName eq \'Storage Account Key Operator Service Role\''
        authorization_mgmt_client = AuthorizationManagementClient(
            user_token_creds, self.config.subscription_id)
        role_id = list(
            authorization_mgmt_client.role_definitions.list(
                scope='/', filter=filter_str))[0].id

        # create a role assignment granting the key vault service principal this role
        role_params = RoleAssignmentCreateParameters(
            role_definition_id=role_id,
            # the Azure Key Vault service id
            principal_id='93c27d83-f79b-4cb2-8dd4-4aa716542e74')
        authorization_mgmt_client.role_assignments.create(
            scope=sa.id,
            role_assignment_name=str(uuid.uuid4()),
            parameters=role_params)

        # since the set_storage_account can only be called by a user account with access to the keys of
        # the storage account, we grant the user that created the storage account access to the vault
        # and add the storage account to the vault
        vault = self.get_sample_vault()

        # grant the user access the vault
        self.grant_access_to_sample_vault(vault, self._user_oid)

        # add the storage account to the vault using the users KeyVaultClient
        print('adding storage acount %s to vault %s' %
              (self.config.storage_account_name, vault.name))
        attributes = StorageAccountAttributes(enabled=True)
        self.keyvault_user_client.set_storage_account(
            vault_base_url=self.sample_vault_url,
            storage_account_name=sa.name,
            resource_id=sa.id,
            active_key_name='key1',
            auto_regenerate_key=True,
            regeneration_period='P30D',
            storage_account_attributes=attributes)
Example #30
0
    def run(self, args):
        """Run the remediation job.
        :param args: List of arguments provided to the job.
        :type args: list.
        :returns: int
        """
        params = self.parse(args[1])
        client_id = os.environ.get("AZURE_CLIENT_ID")
        client_secret = os.environ.get("AZURE_CLIENT_SECRET")
        tenant_id = os.environ.get("AZURE_TENANT_ID")

        # credential for Storage Account and Key Vault management client
        credential = ClientSecretCredential(
            client_id=client_id, client_secret=client_secret, tenant_id=tenant_id,
        )

        # credential for AzureGraphRbacManagementClient
        credentials_graph = ServicePrincipalCredentials(
            client_id=client_id,
            secret=client_secret,
            tenant=tenant_id,
            resource="https://graph.windows.net",
        )

        # credential for SqlManagementClient and
        credentials = ServicePrincipalCredentials(
            client_id=client_id, secret=client_secret, tenant=tenant_id,
        )

        client_storage = StorageManagementClient(credential, params["subscription_id"])

        keyvault_client = KeyVaultManagementClient(
            credential, params["subscription_id"]
        )
        graph_client = GraphRbacManagementClient(
            credentials_graph, tenant_id, base_url=None
        )

        monitor_client = MonitorClient(credential, params["subscription_id"])

        client = SqlManagementClient(
            credentials, params["subscription_id"], base_url=None
        )

        client_authorization = AuthorizationManagementClient(
            credential, params["subscription_id"], api_version="2018-01-01-preview"
        )
        return self.remediate(
            client_id,
            tenant_id,
            credential,
            client,
            client_storage,
            keyvault_client,
            graph_client,
            monitor_client,
            client_authorization,
            params["resource_group_name"],
            params["sql_server_name"],
            params["region"],
            params["subscription_id"],
        )