def test_add_or_update_single_tag(self): """Verifies we can add a new tag to a VM and not modify an existing tag on that resource """ p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.vm', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'cctestvm'} ], 'actions': [ {'type': 'tag', 'tag': 'tag1', 'value': 'value1'} ], }) p.run() # verify that the a new tag is added without modifying existing tags s = Session() client = s.client('azure.mgmt.compute.ComputeManagementClient') vm = client.virtual_machines.get('test_vm', 'cctestvm') self.assertEqual(vm.tags, {'tag1': 'value1', 'testtag': 'testvalue'})
def augment(self, resources): s = Session(resource='https://graph.windows.net') graph_client = GraphRbacManagementClient(s.get_credentials(), s.get_tenant_id()) object_ids = list(set( resource['properties']['principalId'] for resource in resources if resource['properties']['principalId'])) object_params = GetObjectsParameters( include_directory_object_references=True, object_ids=object_ids) aad_objects = graph_client.objects.get_objects_by_object_ids(object_params) try: principal_dics = {aad_object.object_id: aad_object for aad_object in aad_objects} for resource in resources: graph_resource = principal_dics[resource['properties']['principalId']] resource['principalName'] = self.get_principal_name(graph_resource) resource['displayName'] = graph_resource.display_name resource['aadType'] = graph_resource.object_type except CloudError: log.warning('Credentials not authorized for access to read from Microsoft Graph. \n ' 'Can not query on principalName, displayName, or aadType. \n' ) return resources
def test_get_functions_auth_string_overrides(self): with patch('azure.common.credentials.ServicePrincipalCredentials.__init__', autospec=True, return_value=None): with patch.dict(os.environ, { constants.ENV_TENANT_ID: 'tenant', constants.ENV_SUB_ID: 'ea42f556-5106-4743-99b0-c129bfa71a47', constants.ENV_CLIENT_ID: 'client', constants.ENV_CLIENT_SECRET: 'secret', constants.ENV_FUNCTION_TENANT_ID: 'functiontenant', constants.ENV_FUNCTION_SUB_ID: '000000-5106-4743-99b0-c129bfa71a47', constants.ENV_FUNCTION_CLIENT_ID: 'functionclient', constants.ENV_FUNCTION_CLIENT_SECRET: 'functionsecret' }, clear=True): s = Session() auth = s.get_functions_auth_string('000000-5106-4743-99b0-c129bfa71a47') expected = """{ "credentials": { "client_id": "functionclient", "secret": "functionsecret", "tenant": "functiontenant" }, "subscription": "000000-5106-4743-99b0-c129bfa71a47" }""" self.assertEqual(json.loads(auth), json.loads(expected))
def test_auto_tag_add_creator_tag(self, utcnow_mock): """Adds CreatorEmail to a resource group """ p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.resourcegroup', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'test_vm'} ], 'actions': [ {'type': 'auto-tag-user', 'tag': 'CreatorEmail'}, ], }) p.run() # verify CreatorEmail tag set s = Session() client = s.client('azure.mgmt.resource.ResourceManagementClient') rg = [rg for rg in client.resource_groups.list() if rg.name == 'test_vm'][0] self.assertTrue(re.match(self.EMAIL_REGEX, rg.tags['CreatorEmail']))
def test_api_version(self): """Verify we retrieve the correct API version for a resource type""" s = Session() client = s.client('azure.mgmt.resource.ResourceManagementClient') resource = next(client.resources.list()) self.assertTrue(re.match('\\d{4}-\\d{2}-\\d{2}', s.resource_api_version(resource.id)) is not None)
def test_tag_trim_does_nothing_if_space_available(self): """Verifies tag trim returns without trimming tags if the resource has space equal to or greater than the space value. """ s = Session() client = s.client('azure.mgmt.compute.ComputeManagementClient') vm = client.virtual_machines.get('test_vm', 'cctestvm') start_tags = vm.tags # verify there is at least 1 space for a tag self.assertLess(len(start_tags), 15) # trim for space for 1 tag p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.vm', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'cctestvm'} ], 'actions': [ {'type': 'tag-trim', 'space': 1} ], }) p.run() # verify that tags are unchanged vm = client.virtual_machines.get('test_vm', 'cctestvm') self.assertEqual(vm.tags, start_tags)
def setup_account(): # Find actual name of storage account provisioned in our test environment s = Session() client = s.client('azure.mgmt.storage.StorageManagementClient') accounts = list(client.storage_accounts.list()) matching_account = [a for a in accounts if a.name.startswith("cctstorage")] return matching_account[0]
def test_initialize_session_auth_file(self): with patch('azure.common.credentials.ServicePrincipalCredentials.__init__', autospec=True, return_value=None): s = Session(authorization_file=self.authorization_file) self.assertIs(type(s.get_credentials()), ServicePrincipalCredentials) self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID) self.assertEqual(s.get_tenant_id(), 'tenant')
def test_initialize_session_cli(self, mock_run): mock_run.return_value = \ f'{{"id":"{DEFAULT_SUBSCRIPTION_ID}", "tenantId":"{DEFAULT_TENANT_ID}"}}' with patch.dict(os.environ, {}, clear=True): s = Session() self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID) self.assertEqual(s.get_tenant_id(), DEFAULT_TENANT_ID)
def test_get_client_us_gov(self): """Verify we are setting the correct credential scope for us government""" s = Session(cloud_endpoints=AZURE_US_GOV_CLOUD) client = s.client('azure.mgmt.resource.ResourceManagementClient') self.assertEqual(AZURE_US_GOV_CLOUD.endpoints.resource_manager, client._client._base_url) self.assertEqual(AZURE_US_GOV_CLOUD.endpoints.management + ".default", client._client._config.credential_scopes[0])
def test_api_version(self): """Verify we retrieve the correct API version for a resource type""" s = Session() client = s.client('azure.mgmt.resource.ResourceManagementClient') resource = next(client.resources.list()) self.assertTrue( re.match('\\d{4}-\\d{2}-\\d{2}', s.resource_api_version( resource.id)) is not None)
def test_get_client_overrides(self, mock): # Reload the module to re-import patched function reload(sys.modules['c7n_azure.session']) s = Session() client = s.client('azure.mgmt.resource.ResourceManagementClient') self.assertFalse(client._client.config.retry_policy.policy.respect_retry_after_header) self.assertIsNotNone(client._client.orig_send) client._client.send() self.assertTrue(mock.called)
def setup_account(): # Find actual name of storage account provisioned in our test environment s = Session() client = s.client('azure.mgmt.storage.StorageManagementClient') accounts = list(client.storage_accounts.list()) matching_account = [ a for a in accounts if a.name.startswith("cctstorage") ] return matching_account[0]
def test_remove_tags(self): """Verifies we can delete multiple tags from a resource group without modifying existing tags. """ p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.resourcegroup', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'test_vm'} ], 'actions': [ {'type': 'tag', 'tags': {'pre-existing-1': 'to-keep', 'pre-existing-2': 'to-keep', 'added-1': 'to-delete', 'added-2': 'to-delete'}}, ], }) p.run() # verify initial tag set s = Session() client = s.client('azure.mgmt.resource.ResourceManagementClient') rg = [rg for rg in client.resource_groups.list() if rg.name == 'test_vm'][0] start_tags = rg.tags self.assertTrue('pre-existing-1' in start_tags) self.assertTrue('pre-existing-2' in start_tags) self.assertTrue('added-1' in start_tags) self.assertTrue('added-2' in start_tags) p = self.load_policy({ 'name': 'test-azure-remove-tag', 'resource': 'azure.resourcegroup', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'test_vm'} ], 'actions': [ {'type': 'untag', 'tags': ['added-1', 'added-2']} ], }) p.run() # verify tags removed and pre-existing tags not removed rg = [rg for rg in client.resource_groups.list() if rg.name == 'test_vm'][0] # NOQA end_tags = rg.tags self.assertTrue('pre-existing-1' in end_tags) self.assertTrue('pre-existing-2' in end_tags) self.assertTrue('added-1' not in end_tags) self.assertTrue('added-2' not in end_tags)
def test_initialize_msi_auth_system(self): with patch.dict(os.environ, { constants.ENV_USE_MSI: 'true', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID }, clear=True): s = Session() self.assertIsInstance(s.get_credentials()._credential, ManagedIdentityCredential) self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID)
def test_initialize_session_token(self, _1): with patch.dict(os.environ, { constants.ENV_ACCESS_TOKEN: 'token', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID }, clear=True): s = Session() self.assertIs(type(s.get_credentials()), BasicTokenAuthentication) self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID)
def test_initialize_session_auth_file_no_sub(self): s = Session(subscription_id=CUSTOM_SUBSCRIPTION_ID, authorization_file=self.authorization_file_no_sub) self.assertIs(type(s.get_credentials()._credential), ClientSecretCredential) self.assertEqual(s.get_subscription_id(), CUSTOM_SUBSCRIPTION_ID) # will vary between recorded/live auth options but useful to ensure # we ended up with one of the valid values self.assertTrue(s.get_tenant_id() in [DEFAULT_TENANT_ID, 'tenant'])
def test_remove_single_tag(self): """Verifies we can delete a tag to a VM and not modify an existing tag on that resource """ p = self.load_policy({ 'name': 'test-azure-remove-single-tag', 'resource': 'azure.vm', 'filters': [{ 'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'cctestvm' }], 'actions': [{ 'type': 'tag', 'tag': 'tag1', 'value': 'to-delete' }], }) p.run() # verify the initial tag set s = Session() client = s.client('azure.mgmt.compute.ComputeManagementClient') vm = client.virtual_machines.get('test_vm', 'cctestvm') self.assertEqual(vm.tags, { 'tag1': 'to-delete', 'testtag': 'testvalue' }) p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.vm', 'filters': [{ 'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'cctestvm' }], 'actions': [{ 'type': 'untag', 'tags': ['tag1'] }], }) p.run() # verify that the a tag is deleted without modifying existing tags vm = client.virtual_machines.get('test_vm', 'cctestvm') self.assertEqual(vm.tags, {'testtag': 'testvalue'})
def test_tag_trim_space_0_removes_all_tags_but_preserve(self): """Verifies tag trim removes all other tags but tags listed in preserve """ # Add tags to trim p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.vm', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'cctestvm'} ], 'actions': [ {'type': 'tag', 'tags': {'tag-to-trim1': 'value1', 'tag-to-trim2': 'value2', 'tag-to-trim3': 'value3'}} ], }) p.run() # verify initial tags contain more than testtag s = Session() client = s.client('azure.mgmt.compute.ComputeManagementClient') vm = client.virtual_machines.get('test_vm', 'cctestvm') self.assertTrue('tag-to-trim1' in vm.tags) self.assertTrue('tag-to-trim2' in vm.tags) self.assertTrue('tag-to-trim3' in vm.tags) self.assertTrue('testtag' in vm.tags) p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.vm', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'cctestvm'} ], 'actions': [ {'type': 'tag-trim', 'space': 0, 'preserve': ['testtag'] } ], }) p.run() # verify all tags trimmed but testtag vm = client.virtual_machines.get('test_vm', 'cctestvm') self.assertEqual(vm.tags, {'testtag': 'testvalue'})
def test_auto_tag_update_false_noop_for_existing_tag(self, utcnow_mock): """Adds CreatorEmail to a resource group """ # setup by adding an existing CreatorEmail tag p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.resourcegroup', 'filters': [{ 'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'test_vm' }], 'actions': [ { 'type': 'tag', 'tag': 'CreatorEmail', 'value': 'do-not-modify' }, ], }) p.run() p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.resourcegroup', 'filters': [{ 'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'test_vm' }], 'actions': [{ 'type': 'auto-tag-user', 'tag': 'CreatorEmail', 'update': False, 'days': 10 }], }) p.run() # verify CreatorEmail tag was not modified s = Session() client = s.client('azure.mgmt.resource.ResourceManagementClient') rg = [ rg for rg in client.resource_groups.list() if rg.name == 'test_vm' ][0] self.assertEqual(rg.tags['CreatorEmail'], 'do-not-modify')
def setUp(self): super(AzureEventSubscriptionsTest, self).setUp() self.session = Session() account = self.setup_account() queue_name = 'cctesteventsub' StorageUtilities.create_queue_from_storage_account(account, queue_name, self.session) event_sub_destination = StorageQueueEventSubscriptionDestination( resource_id=account.id, queue_name=queue_name) AzureEventSubscription.create(event_sub_destination, self.event_sub_name, self.session.get_subscription_id())
def test_initialize_session_token(self): with patch.dict(os.environ, { constants.ENV_ACCESS_TOKEN: 'token', constants.ENV_SUB_ID: 'ea42f556-5106-4743-99b0-c129bfa71a47' }, clear=True): s = Session() self.assertIs(type(s.get_credentials()), BasicTokenAuthentication) self.assertEqual(s.get_subscription_id(), 'ea42f556-5106-4743-99b0-c129bfa71a47')
def test_initialize_session_token(self): with patch.dict(os.environ, { constants.ENV_ACCESS_TOKEN: 'token', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID }, clear=True): s = Session() self.assertIsNone(s.get_credentials()._credential) self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID) self.assertEqual(s.get_credentials().get_token(), AccessToken('token', 0))
def test_initialize_session_token(self): with patch.dict(os.environ, { constants.ENV_ACCESS_TOKEN: 'token', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID }, clear=True): s = Session() self.assertIs(type(s.get_credentials()), BasicTokenAuthentication) self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID)
def test_initialize_msi_auth_system(self): with patch('msrestazure.azure_active_directory.MSIAuthentication.__init__', autospec=True, return_value=None): with patch.dict(os.environ, { constants.ENV_USE_MSI: 'true', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID }, clear=True): s = Session() self.assertIs(type(s.get_credentials()), MSIAuthentication) self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID)
def test_tag_trim_removes_tags_for_space(self): """Verifies tag trim removes tags when the space value and number of tags on the resource are greater than the max tag value (15) """ # Add tags to trim p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.vm', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'cctestvm'} ], 'actions': [ {'type': 'tag', 'tags': {'tag-to-trim1': 'value1', 'tag-to-trim2': 'value2'}} ], }) p.run() # verify more than 1 tag on resource s = Session() client = s.client('azure.mgmt.compute.ComputeManagementClient') vm = client.virtual_machines.get('test_vm', 'cctestvm') self.assertTrue(len(vm.tags) > 1) p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.vm', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'cctestvm'} ], 'actions': [ {'type': 'tag-trim', 'space': 14, 'preserve': ['testtag'] } ], }) p.run() # verify that tags were trimmed to # have 14 spaces and 1 preserved vm = client.virtual_machines.get('test_vm', 'cctestvm') self.assertEqual(len(vm.tags), 1)
def test_initialize_msi_auth_system(self): with patch('msrestazure.azure_active_directory.MSIAuthentication.__init__', autospec=True, return_value=None): with patch.dict(os.environ, { constants.ENV_USE_MSI: 'true', constants.ENV_SUB_ID: 'ea42f556-5106-4743-99b0-c129bfa71a47' }, clear=True): s = Session() self.assertIs(type(s.get_credentials()), MSIAuthentication) self.assertEqual(s.get_subscription_id(), 'ea42f556-5106-4743-99b0-c129bfa71a47')
def test_initialize_session_auth_file_no_sub(self): with patch('azure.common.credentials.ServicePrincipalCredentials.__init__', autospec=True, return_value=None): s = Session(subscription_id=CUSTOM_SUBSCRIPTION_ID, authorization_file=self.authorization_file_no_sub) self.assertIs(type(s.get_credentials()), ServicePrincipalCredentials) self.assertEqual(s.get_subscription_id(), CUSTOM_SUBSCRIPTION_ID) # will vary between recorded/live auth options but useful to ensure # we ended up with one of the valid values self.assertTrue(s.get_tenant_id() in [DEFAULT_TENANT_ID, 'tenant'])
def test_initialize_session_principal(self): with patch.dict(os.environ, { constants.ENV_TENANT_ID: DEFAULT_TENANT_ID, constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID, constants.ENV_CLIENT_ID: 'client', constants.ENV_CLIENT_SECRET: 'secret' }, clear=True): s = Session() self.assertIs(type(s.get_credentials()._credential), ClientSecretCredential) self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID) self.assertEqual(s.get_tenant_id(), DEFAULT_TENANT_ID)
def test_initialize_session_msi_authentication_error(self, mock_log, mock_cred): with self.assertRaises(SystemExit): mock_cred.side_effect = HTTPError() with patch.dict(os.environ, { constants.ENV_USE_MSI: 'true', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID }, clear=True): s = Session() s.get_subscription_id() mock_log.assert_called_once_with('Failed to authenticate with MSI')
def test_deploy_webapp(self): s = Session() web_client = s.client('azure.mgmt.web.WebSiteManagementClient') service_plan = web_client.app_service_plans.get( CONST_GROUP_NAME, 'cloud-custodian-test') self.assertIsNotNone(service_plan) webapp_name = 'test-deploy-webapp' self.functionapp_util.deploy_webapp(webapp_name, CONST_GROUP_NAME, service_plan, 'cloudcustodiantest') wep_app = web_client.web_apps.get(CONST_GROUP_NAME, webapp_name) self.assertIsNotNone(wep_app)
def test_initialize_session_token(self): with patch.dict( os.environ, { constants.ENV_ACCESS_TOKEN: 'token', constants.ENV_SUB_ID: 'ea42f556-5106-4743-99b0-c129bfa71a47' }, clear=True): s = Session() self.assertIs(type(s.get_credentials()), BasicTokenAuthentication) self.assertEqual(s.get_subscription_id(), 'ea42f556-5106-4743-99b0-c129bfa71a47')
def test_initialize_msi_auth_user(self): with patch.dict(os.environ, { constants.ENV_USE_MSI: 'true', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID, constants.ENV_CLIENT_ID: 'client' }, clear=True): s = Session() self.assertIsInstance(s.get_credentials()._credential, ManagedIdentityCredential) # self.assertEqual( # s.get_credentials()._credential._credential._identity_config["client_id"], # 'client') self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID)
def test_add_or_update_tags(self): """Adds tags to an empty resource group, then updates one tag and adds a new tag """ p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.resourcegroup', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'test_vm'} ], 'actions': [ {'type': 'tag', 'tags': {'pre-existing-1': 'unmodified', 'pre-existing-2': 'unmodified'}}, ], }) p.run() # verify initial tag set s = Session() client = s.client('azure.mgmt.resource.ResourceManagementClient') rg = [rg for rg in client.resource_groups.list() if rg.name == 'test_vm'][0] self.assertEqual(rg.tags, {'pre-existing-1': 'unmodified', 'pre-existing-2': 'unmodified'}) p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.resourcegroup', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'test_vm'} ], 'actions': [ {'type': 'tag', 'tags': {'tag1': 'value1', 'pre-existing-1': 'modified'}} ], }) p.run() # verify modified tags rg = [rg for rg in client.resource_groups.list() if rg.name == 'test_vm'][0] # NOQA self.assertEqual( rg.tags, {'tag1': 'value1', 'pre-existing-1': 'modified', 'pre-existing-2': 'unmodified'})
def test_initialize_session_cli_error(self, mock_log, mock_cli_creds): with self.assertRaises(SystemExit): mock_cli_creds.side_effect = CLIError("Bad CLI credentials") with patch.dict(os.environ, { constants.ENV_TENANT_ID: 'tenant', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID, }, clear=True): s = Session() s.get_subscription_id() mock_log.assert_called_once_with('Failed to authenticate with CLI credentials. ' 'Bad CLI credentials')
def test_initialize_session_principal(self): with patch('azure.common.credentials.ServicePrincipalCredentials.__init__', autospec=True, return_value=None): with patch.dict(os.environ, { constants.ENV_TENANT_ID: DEFAULT_TENANT_ID, constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID, constants.ENV_CLIENT_ID: 'client', constants.ENV_CLIENT_SECRET: 'secret' }, clear=True): s = Session() self.assertIs(type(s.get_credentials()), ServicePrincipalCredentials) self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID) self.assertEqual(s.get_tenant_id(), DEFAULT_TENANT_ID)
def test_initialize_session_principal(self): with patch('azure.common.credentials.ServicePrincipalCredentials.__init__', autospec=True, return_value=None): with patch.dict(os.environ, { constants.ENV_TENANT_ID: 'tenant', constants.ENV_SUB_ID: 'ea42f556-5106-4743-99b0-c129bfa71a47', constants.ENV_CLIENT_ID: 'client', constants.ENV_CLIENT_SECRET: 'secret' }, clear=True): s = Session() self.assertIs(type(s.get_credentials()), ServicePrincipalCredentials) self.assertEqual(s.get_subscription_id(), 'ea42f556-5106-4743-99b0-c129bfa71a47')
def __init__(self, storage_id, queue_name, policy_uri, log_group=None, metrics=None, output_dir=None): logging.basicConfig(level=logging.INFO, format='%(message)s') log.info("Running Azure Cloud Custodian Self-Host") resources.load_available() self.session = local_session(Session) self.storage_session = self.session storage_subscription_id = ResourceIdParser.get_subscription_id(storage_id) if storage_subscription_id != self.session.subscription_id: self.storage_session = Session(subscription_id=storage_subscription_id) # Load configuration self.options = Host.build_options(output_dir, log_group, metrics) self.policy_storage_uri = policy_uri self.event_queue_id = storage_id self.event_queue_name = queue_name # Default event queue name is the subscription ID if not self.event_queue_name: self.event_queue_name = self.session.subscription_id # Prepare storage bits self.policy_blob_client = None self.blob_cache = {} self.queue_storage_account = self.prepare_queue_storage( self.event_queue_id, self.event_queue_name) self.queue_service = None # Register event subscription self.update_event_subscription() # Policy cache and dictionary self.policy_cache = tempfile.mkdtemp() self.policies = {} # Configure scheduler self.scheduler = BlockingScheduler(Host.get_scheduler_config()) logging.getLogger('apscheduler.executors.default').setLevel(logging.ERROR) logging.getLogger('apscheduler').setLevel(logging.ERROR) # Schedule recurring policy updates self.scheduler.add_job(self.update_policies, 'interval', seconds=policy_update_seconds, id="update_policies", next_run_time=datetime.now(), executor='threadpool') # Schedule recurring queue polling self.scheduler.add_job(self.poll_queue, 'interval', seconds=queue_poll_seconds, id="poll_queue", executor='threadpool') self.scheduler.start()
def test_auto_tag_update_false_noop_for_existing_tag(self, utcnow_mock): """Adds CreatorEmail to a resource group """ # setup by adding an existing CreatorEmail tag p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.resourcegroup', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'test_vm'} ], 'actions': [ {'type': 'tag', 'tag': 'CreatorEmail', 'value': 'do-not-modify'}, ], }) p.run() p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.resourcegroup', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'test_vm'} ], 'actions': [ {'type': 'auto-tag-user', 'tag': 'CreatorEmail', 'update': False, 'days': 10} ], }) p.run() # verify CreatorEmail tag was not modified s = Session() client = s.client('azure.mgmt.resource.ResourceManagementClient') rg = [rg for rg in client.resource_groups.list() if rg.name == 'test_vm'][0] self.assertEqual(rg.tags['CreatorEmail'], 'do-not-modify')
def test_initialize_session_msi_authentication_error( self, mock_log, mock_cred): with self.assertRaises(SystemExit): mock_cred.side_effect = HTTPError() with patch.dict(os.environ, { constants.ENV_USE_MSI: 'true', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID }, clear=True): s = Session() s.get_subscription_id() mock_log.assert_called_once_with( 'Azure Authentication Failure\n' 'Error: Could not authenticate using managed service identity (system identity)' )
def test_initialize_msi_auth_user(self): with patch( 'msrestazure.azure_active_directory.MSIAuthentication.__init__', autospec=True, return_value=None): with patch.dict(os.environ, { constants.ENV_USE_MSI: 'true', constants.ENV_SUB_ID: 'ea42f556-5106-4743-99b0-c129bfa71a47', constants.ENV_CLIENT_ID: 'client' }, clear=True): s = Session() self.assertIs(type(s.get_credentials()), MSIAuthentication) self.assertEqual(s.get_subscription_id(), 'ea42f556-5106-4743-99b0-c129bfa71a47')
def test_initialize_session_kv_authentication_error(self, mock_log, mock_get_kv_secret): with self.assertRaises(SystemExit): mock_get_kv_secret.side_effect = HTTPError() with patch.dict(os.environ, { constants.ENV_TENANT_ID: 'tenant', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID, constants.ENV_KEYVAULT_CLIENT_ID: 'kv_client', constants.ENV_KEYVAULT_SECRET_ID: 'kv_secret' }, clear=True): s = Session() s.get_subscription_id() mock_log.assert_called_once_with( 'Failed to retrieve SP credential from ' 'Key Vault with client id: kv_client')
def enhance_policies(self, access_policies): if self.graph_client is None: s = Session(resource='https://graph.windows.net') self.graph_client = GraphRbacManagementClient(s.get_credentials(), s.get_tenant_id()) # Retrieve graph objects for all object_id object_ids = [p['objectId'] for p in access_policies] # GraphHelper.get_principal_dictionary returns empty AADObject if not found with graph # or if graph is not available. principal_dics = GraphHelper.get_principal_dictionary(self.graph_client, object_ids) for policy in access_policies: aad_object = principal_dics[policy['objectId']] policy['displayName'] = aad_object.display_name policy['aadType'] = aad_object.object_type policy['principalName'] = GraphHelper.get_principal_name(aad_object) return access_policies
def augment(self, resources): s = Session(resource='https://graph.windows.net') graph_client = GraphRbacManagementClient(s.get_credentials(), s.get_tenant_id()) object_ids = list(set( resource['properties']['principalId'] for resource in resources if resource['properties']['principalId'])) principal_dics = GraphHelper.get_principal_dictionary(graph_client, object_ids) for resource in resources: if resource['properties']['principalId'] in principal_dics.keys(): graph_resource = principal_dics[resource['properties']['principalId']] if graph_resource.object_id: resource['principalName'] = GraphHelper.get_principal_name(graph_resource) resource['displayName'] = graph_resource.display_name resource['aadType'] = graph_resource.object_type return resources
def test_get_functions_auth_string(self): with patch('azure.common.credentials.ServicePrincipalCredentials.__init__', autospec=True, return_value=None): with patch.dict(os.environ, { constants.ENV_TENANT_ID: 'tenant', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID, constants.ENV_CLIENT_ID: 'client', constants.ENV_CLIENT_SECRET: 'secret' }, clear=True): s = Session() auth = s.get_functions_auth_string(CUSTOM_SUBSCRIPTION_ID) expected = {"credentials": {"client_id": "client", "secret": "secret", "tenant": "tenant"}, "subscription": CUSTOM_SUBSCRIPTION_ID} self.assertEqual(json.loads(auth), expected)
def test_get_function_target_subscription(self): with patch('azure.common.credentials.ServicePrincipalCredentials.__init__', autospec=True, return_value=None): with patch.dict(os.environ, { constants.ENV_TENANT_ID: 'tenant', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID, constants.ENV_CLIENT_ID: 'client', constants.ENV_CLIENT_SECRET: 'secret' }, clear=True): s = Session() self.assertEqual(s.get_function_target_subscription_name(), DEFAULT_SUBSCRIPTION_ID) self.assertEqual(s.get_function_target_subscription_ids(), [DEFAULT_SUBSCRIPTION_ID]) with patch.dict(os.environ, { constants.ENV_TENANT_ID: 'tenant', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID, constants.ENV_CLIENT_ID: 'client', constants.ENV_CLIENT_SECRET: 'secret', constants.ENV_FUNCTION_SUB_ID: CUSTOM_SUBSCRIPTION_ID }, clear=True): s = Session() self.assertEqual(s.get_function_target_subscription_name(), CUSTOM_SUBSCRIPTION_ID) self.assertEqual(s.get_function_target_subscription_ids(), [CUSTOM_SUBSCRIPTION_ID]) with patch.dict(os.environ, { constants.ENV_TENANT_ID: 'tenant', constants.ENV_SUB_ID: DEFAULT_SUBSCRIPTION_ID, constants.ENV_CLIENT_ID: 'client', constants.ENV_CLIENT_SECRET: 'secret', constants.ENV_FUNCTION_MANAGED_GROUP_NAME: 'test' }, clear=True): with patch('c7n_azure.utils.ManagedGroupHelper.get_subscriptions_list', return_value=[]): s = Session() self.assertEqual(s.get_function_target_subscription_name(), 'test') self.assertEqual(s.get_function_target_subscription_ids(), [])
def test_removal_does_not_raise_on_nonexistent_tag(self): """Verifies attempting to delete a tag that is not on the resource does not throw an error """ p = self.load_policy({ 'name': 'test-azure-tag', 'resource': 'azure.vm', 'filters': [ {'type': 'value', 'key': 'name', 'op': 'eq', 'value_type': 'normalize', 'value': 'cctestvm'} ], 'actions': [ {'type': 'untag', 'tags': ['tag-does-not-exist']}, ], }) # verify initial tag set s = Session() client = s.client('azure.mgmt.compute.ComputeManagementClient') vm = client.virtual_machines.get('test_vm', 'cctestvm') start_tags = vm.tags self.assertTrue('tag-does-not-exist' not in start_tags) raised = False try: p.run() except KeyError: raised = True # verify no exception raised and no changes to tags on resource vm = client.virtual_machines.get('test_vm', 'cctestvm') self.assertFalse(raised) self.assertEqual(vm.tags, start_tags)
def test_get_session_for_resource(self): s = Session() resource_session = s.get_session_for_resource(constants.RESOURCE_STORAGE) self.assertEqual(resource_session.resource_namespace, constants.RESOURCE_STORAGE)
def test_api_version(self): """Verify we retrieve the correct API version for a resource type""" s = Session() client = s.client('azure.mgmt.resource.ResourceManagementClient') resource = next(client.resources.list()) self.assertEqual('2018-04-01', s.resource_api_version(resource.id))