Unsafe Component Detection¶
NVFLARE is based on a componentized architecture in that FL jobs are performed by components that are configured in configuration files. These components are created at the beginning of job execution. To address the issue of components potentially being unsafe and leaking sensitive information, NVFLARE uses an event based solutionm.
NVFLARE has a very powerful and flexible event mechanism that allows custom code to be plugged into defined moments of system workflow (e.g. start/end of the job, before/after a task is executed, etc.). At such moments, NVFLARE fires events and invokes FLComponent objects that handle these events.
The BEFORE_BUILD_COMPONENT
event type can allow a custom FLComponent to detect unsafe job components during the time of configuration processing. This event
type is fired before the configuration processor starts to build a job component (executor, filter, etc.).
Detect Unsafe Job Components¶
To detect unsafe job components, the user simply needs to create a custom FLComponent object that handles this event, as shown in the following ComponentChecker example:
from nvflare.apis.event_type import EventType
from nvflare.apis.fl_component import FLComponent
from nvflare.apis.fl_constant import FLContextKey
from nvflare.apis.fl_context import FLContext
from nvflare.apis.fl_exception import UnsafeComponentError
class ComponentChecker(FLComponent):
def handle_event(self, event_type: str, fl_ctx: FLContext):
prop_keys = fl_ctx.get_prop_keys()
if event_type == EventType.BEFORE_BUILD_COMPONENT:
print(f"ComponentChecker: fl_ctx props: {prop_keys}")
comp_config = fl_ctx.get_prop(FLContextKey.COMPONENT_CONFIG)
print(f"Comp Config: {comp_config}")
raise UnsafeComponentError("client encountered bad component")
The important points are:
The class must extend FLComponent
It defines the handle_event method, following the exact signature
It checks the event_type to be
EventType.BEFORE_BUILD_COMPONENT
.It checks the component being built based on the information provided in the fl_ctx. There are many properties in fl_ctx. The most important ones are the
COMPONENT_CONFIG
that is a dict of the component’s configuration data. The fl_ctx also hasWORKSPACE_OBJECT
that allows you to access any file in the job’s workspace.If any issue is detected with the component to be built, you raise the
UnsafeComponentError
exception with a meaningful text.
The following properties in the fl_ctx could be helpful too:
FLContextKey.COMPONENT_NODE
- This gives you the information about the component’s location in the config structure (which could be viewed as a tree).
FLContextKey.CONFIG_CTX
- This gives you information about the entire config structure.
FLContextKey.CURRENT_JOB_ID
- The ID of the current job.
FLContextKey.JOB_META
- This is a dict that contains meta information (e.g. job submitter’s name, org and role) about the current job.
FLContextKey.WORKSPACE_OBJECT
- This object provides many convenience methods to determine the paths of files in the workspace
Install Your Component Checker¶
Once you define your component checker (you can name your class any way you want - does not have to be ComponentChecker), you need to install it to your FL site(s).
First of all, your custom code could be included as part of your FL docker, depending on how you manage the docker. If this is not
possible, then you can include it in the FL site’s <workspace_root>/local/custom
folder.
Second, include this custom component in your site’s job_resources.json
, as shown here:
{
"format_version": 2,
"components": [
{
"id": "comp_checker",
"path": "comp_auth.ComponentChecker"
}
]
}
Your site’s workspace should look like this:
workspace_root
local
resources.json
job_resources.json
...
custom
comp_auth.py
startup
...