def __init__( self, account_id, google_project_id, google_cloud_manager=None, google_project_number=None, *args, **kwargs ): self.account_id = account_id self.google_project_id = google_project_id # default to the given project id if not provided self.google_project_number = google_project_number or google_project_id self.google_cloud_manager = google_cloud_manager or GoogleCloudManager( google_project_id ) super(GoogleServiceAccountValidity, self).__init__(*args, **kwargs) # setup default values for error information, will get updated in # check_validity self._info["owned_by_project"] = None self._info["valid_type"] = None self._info["no_external_access"] = None self._info["policy_accessible"] = None
def __init__( self, google_project_id, new_service_account=None, new_service_account_access=None, user_id=None, google_cloud_manager=None, *args, **kwargs ): """ Initialize Args: google_project_id (str): Google project identifier new_service_account (str, optional): an additional service account identifier (ex: email) to include when checking access. You can provide this without actually giving it access to check if access will be valid new_service_account_access (List(str), optional): List of Project.auth_ids to attempt to provide the new service account access to user_id (None, optional): User requesting validation. ONLY pass this if you want to check if the user is a member of this project. """ self.google_project_id = google_project_id self.new_service_account = new_service_account self.new_service_account_access = new_service_account_access or [] self.user_id = user_id self.google_cloud_manager = google_cloud_manager or GoogleCloudManager( google_project_id ) super(GoogleProjectValidity, self).__init__(*args, **kwargs) # setup default values for error information, will get updated in # check_validity self._info["user_has_access"] = None self._info["monitor_has_access"] = None self._info["valid_parent_org"] = None self._info["valid_member_types"] = None self._info["members_exist_in_fence"] = None self._info["new_service_account"] = {} self._info["service_accounts"] = {} self._info["access"] = {}
def check_validity( self, early_return=True, check_type=True, check_external_access=True, check_policy_accessible=True, ): logger.debug( "Validating Google Service Account {} for Google Project {}.".format( self.account_id, self.google_project_id ) ) self.google_cloud_manager.open() # check ownership logger.debug( "Determining if {} is owned by the Google Project.".format(self.account_id) ) is_owned_by_google_project = is_service_account_from_google_project( self.account_id, self.google_project_id, self.google_project_number ) self.set("owned_by_project", is_owned_by_google_project) if not is_owned_by_google_project: logger.warning( "INVALID SA {}, it is NOT owned by the Google Project {}.".format( self.account_id, self.google_project_id ) ) if early_return: self.google_cloud_manager.close() return # select the GCM to use for the remainder of the checks # if the account is not owned by the google project then # it is invalid, however, if Fence has access to the SA's # project, we can still check the other conditions if is_owned_by_google_project: gcm = self.google_cloud_manager else: self.google_cloud_manager.close() try: # check to see if we can access the project the SA belongs to project_id = self.account_id.split("@")[-1].split(".")[0] gcm = GoogleCloudManager(project_id) gcm.open() except Exception: logger.debug( "Could not access the Google Project for Service " "Account {}. Unable to continue validity " "checkingwithout access to the project, " "early exit.".format(self.account_id) ) return # check if the SA's policy is accessible policy_accessible = None sa_policy = None if check_policy_accessible: try: policy_accessible = True sa_policy = get_service_account_policy(self.account_id, gcm) except Exception: policy_accessible = False gcm.close() return finally: self.set("policy_accessible", policy_accessible) if check_external_access: if not policy_accessible: logger.warning( "Invalid function use. External Access check requires " "Service Account Policy & may fail if policy is not " "accessible. If you want to check external access, make " "sure you are also checking policy_accessible. " ) gcm.close() return no_external_access = not ( service_account_has_external_access(self.account_id, gcm, sa_policy) ) self.set("no_external_access", no_external_access) if not no_external_access: logger.warning( "INVALID SA {}, it has external access " "(keys generated or roles on it).".format(self.account_id) ) if early_return: gcm.close() return # check if the SA is an allowed type if check_type: if not policy_accessible: logger.warning( "Policy access was not checked. If the service account's " "policy is not accessible or the service account does not " "exist, this check may fail." ) # don't return early, we can still check type without checking # policy, however, if the SA doesn't exist, this will fail valid_type = is_valid_service_account_type(self.account_id, gcm) self.set("valid_type", valid_type) if not valid_type: logger.warning( "INVALID SA {}, it is not a valid SA type.".format(self.account_id) ) if early_return: gcm.close() return gcm.close()