Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Propose and evaluate different designs #93

Closed
2 tasks done
Tracked by #83
AlexRuiz7 opened this issue Aug 30, 2023 · 2 comments
Closed
2 tasks done
Tracked by #83

Propose and evaluate different designs #93

AlexRuiz7 opened this issue Aug 30, 2023 · 2 comments
Assignees
Labels

Comments

@AlexRuiz7
Copy link
Member

AlexRuiz7 commented Aug 30, 2023

Description

The first step of #83 is to generate and evaluate different designs to integrate our modules into the platform menu.

Tasks

  • Generate at least 3 designs and comment its pros and cons
  • Propose one of them as candidate.
@AlexRuiz7 AlexRuiz7 mentioned this issue Aug 30, 2023
3 tasks
@AlexRuiz7
Copy link
Member Author

AlexRuiz7 commented Aug 30, 2023

Summary

Objective

A first proposal of how to organize the navigation drawer entries could be the following:

Category Name Section in monolith plugin
Endpoint security Overview Modules directory
Endpoint security Endpoints summary Agents
Endpoint security Integrity monitoring Modules > Integrity monitoring
Endpoint security Policy monitoring Modules > Policy monitoring
Endpoint security Security Configuration Assessment Modules > Security Configuration Assessment
Endpoint security System auditing Modules > System auditing
Endpoint security OpenSCAP Modules > OpenSCAP
Endpoint security CIS-CAT Modules > CIS-CAT
Thread intelligence Security events Modules > Security events
Thread intelligence Vulnerabilities Modules > Vulnerabilities
Thread intelligence MITRE ATT&CK Modules > MITRE ATT&CK
Thread intelligence Virustotal Modules > Virustotal
Security operations PCI DSS Modules > PCI DSS
Security operations GDPR Modules > GDPR
Security operations HIPAA Modules > HIPAA
Security operations NIST 800-53 Modules > NIST 800-53
Security operations TSC Modules > TSC
Security operations IT Hygiene Agents > {agent_id}
Security operations Osquery Modules > Osquery
Cloud security AWS Modules > AWS
Cloud security Google Cloud Modules > Google Cloud
Cloud security GitHub Modules > GitHub
Cloud security Office365 Modules > Office365
Cloud security Docker listener Modules > Docker listener
Server management Rules Management > Rules
Server management Decoders Management > Decoders
Server management CDB lists Management > CDB lists
Server management Groups Management > Groups
Server management Status Management > Status
Server management Cluster Management > Cluster
Server management Statistics Management > Statistics
Server management Logs Management > Logs
Server management Reporting Management > Reporting
Server management Settings Management > Configuration
Server management API console Tools > API console
Server management Ruleset test Tools > Ruleset test
Server management RBAC Security
Management Server API Settings > API configuration
Management Modules Settings > Modules
Management Server data Settings > Sample data
Management Configuration Settings > Configuration
Management Logs Settings > Logs
Management About Settings > About

Design proposals

There are multiple choices we can make to implement this:

  1. Register the monolith plugin multiple times changing the category, so they appear in the navigation drawer as seen in table above.
  2. Split the Wazuh plugin into small pieces, each one registering itself into the navigation drawer.
  3. Create a new plugin with the purpose of creating this menu.

Multi-app plugin

We can register the monolith modules into the global navigation drawer. This is, register the current app several times with different entry points (modules) and categories.

Pros
  • Relatively small development size.
  • First step forward into the modularization of the app.
Cons
  • Dragging of technical debt.
  • Temporal solution (will be abandon once the app is modularized).
  • Increases technical debt (suboptimal solution).

Modularization of the monolith

We could split the current monolith app into several plugins.

Pros
  • Modularization. Smaller pieces of code improve maintainability and scalability.
  • Reduce of technical debt.
Cons
  • Large size development.
  • Very high risk of problems arising during development.
  • This approach will require collateral changes that are out of the scope of this project.

Router plugin

We could create a new plugin that would manage all the redirections to the monolith plugin (routing).

Pros
  • New plugin, so no modification required in the monolith app aside from the dropdown menu removal.
  • Centralized requests management.
Cons
  • Medium size development.
  • Adds complexity in exchange for small retribution.
  • Brand-new design. No examples we can follow.

Conclusion

After evaluating these 3 proposals, we think that proposal nr.1 .- Multi-app plugin. Although we are aware that this solution is suboptimal, as it drags and adds to the technical debt, we think this is the most achievable approach right now, as it is the simplest one and has the lowest risks. Also, this means a first step towards the modularization of the app, which is our final goal.

@AlexRuiz7
Copy link
Member Author

AlexRuiz7 commented Aug 30, 2023

TL;DR

Research

Performed by @Desvelao

Research viability of the router plugin design

The platform menu displays all the registered and visible applications. A plugin can register any number of applications in the platform menu. The app registration needs to define what will be rendered when the user accesses the menu.

This means that if we do a plugin to register all the applications, then it must have access to the render methods of them. The rendering method can come from other plugins or itself. If they come from other plugins, this creates more dependency between these plugins.

The menu as a standalone plugin can need more logic than if each plugin manages the application registration.

I think that @asteriscos was working in a POC to register multiple applications. It would be interesting to know what approach followed.

Adding multiple applications breaks some features related to:

  • visibility of application: in the current application, it can be disabled for some users through Wazuh indexer roles using the disabled_roles setting of the wazuh.yml
  • visibility of applications related to old modules:
    • on adding new host): extensions.* in wazuh.yml
    • by host: in Settings > Modules
    • by selected agent compatibility

Settings > Modules is not included in the proposition.

Other problems related to the proposition:

  • Redux store is recreated if changing the application
  • The feature to disable the plugin should be adapted or removed as necessary.
  • Settings > Miscellaneous section needs to be included in the Configuration application.
  • Rename OpenSearch Dashboards and OpenSearch Plugins plugin categories. This has to be done in the Wazuh dashboard application and security plugins.

Originally posted by @Desvelao in #83 (comment)

Research viability of the modularization of the monolith design

The current plugin is a monolith and this can generate multiple problems if we want to decouple into different applications if this architecture is kept as mentioned ones:

  • The health check page redirections.
  • The AngularJS routing problems.
  • The embedded Discover URLs.
Health check page redirections.

This is a page that does some checks and creates or updates some elements that are needed to work the plugin.

Each route of the current plugin can do some checks. If some of them fail, then a redirection to the health check page will be done. This means we should decide how to accommodate the health check in the different applications. It could be a different application or a route in each future application if we want to keep the current logic.

The AngularJS routing problems

The current plugin uses AngularJS as base, despite part of the application being migrated to ReactJS. The routing is done with AngularJS.

The embedded Discover URLs

The Events tab of each module uses the URL to set the filters.

Originally posted by @Desvelao in #83 (comment)

Research viability of the multi-app design

@asteriscos and I were researching how to create the applications in the side menu, and clicking on them redirects to them.

This approach does the new applications redirect to the monolith plugin when the link in the side menu is clicked on. The monolith plugin should be hidden.

Pros:

  • The monolith application does not need to change the redirection.

Cons:

  • When the user accesses an application, get a new API token. This means if the user is changing between applications, he/she will get new tokens.
Problems
  • Redux store is recreated if changing the application

I found a problem with this approach that causes the plugin to be initialized each time the user uses the side menu links to navigate to the applications. This means the Redux store is reset. For some application flow, as the selected agent, is important to keep this state between the navigation. There are more states that should be kept in the navigation. To work around this, we should init the Redux store with a similar state to the previous one.

Screenshots

image

Implementation

Create the application that redirects to the monolith application:

core.application.register({
  id,
  title,
  mount: async (params: AppMountParameters) => {
    window.location.href = href; // e.g.: /app/wazuh#/agents
  },
  category,
});

Hide the monolith application:

import {
  AppNavLinkStatus,
} from '../../../src/core/public';
core.application.register({
  id: `wazuh`,
  title: 'Wazuh',
  navLinkStatus: AppNavLinkStatus.hidden,
 // rest of properties
})

Add applications to base Management category:

import { DEFAULT_APP_CATEGORIES,} from '../../../src/core/public';

core.application.register({
  id,
  title,
  mount: async (params: AppMountParameters) => {
    window.location.href = href;
  },
  category: DEFAULT_APP_CATEGORIES.management,
})

Change the routes dynamically:

// public/services/routes.ts
const redirectTo: getApplicationRedirectTo()
// router definition
.when('/', {
      redirectTo,
      outerAngularWrapperRoute: true,
    })
    .when('', {
      redirectTo,
      outerAngularWrapperRoute: true,
    })
    .otherwise({
      redirectTo,
      outerAngularWrapperRoute: true,
    });

getRootRedirectTo is a getter. Use a setter when the application is mounted in the mount method:

// public/plugin.ts
mount: (params){
  setApplicationRedirectTo(redirectToRoot);
  // rest of logic
}

Create the getter/setter:

// public/kibana_services.js
export const [getApplicationRedirectTo, setApplicationRedirectTo] =
  createGetterSetter<any>('WzApplicationRedirectTo');

I was testing this trying to keep the shared state of the selected agent that is stored in Redux store. When I change from a Wazuh application to another one, despite the agentId parameter being added to the URL, it disappears due to the page being refreshed https://github.com/wazuh/wazuh-kibana-app/blob/4.6.0/plugins/main/public/plugin.ts#L96

window.location.reload()

Reloading the page is used in other situations. So, fixing is not easy because the Redux store is kept, and the page can't be refreshed. Both situations are mutually exclusive.

If we need to want to use the Redux store to share critical state, then it seems the page should not be refreshed. As the user can refresh manually the page, this could cause some problems, so it seems these states should be managed in another way, such as local storage/session storage or URL.

Update 2023/08/21
In a meeting with @asteriscos , we tried to use the session store for the selected agent. So the selected agent is stored in the Redux store and session storage. If the page is refreshed (by the user or the application itself), then the Redux store will use the value of the selected agent in the session storage to initiate the Redux store. A mechanism that exists in the current application will set the agentId query parameter in the URL if the agent data is stored in the Redux store. We will continue with this approach.

// plugins/main/public/redux/reducers/appStateReducers.js
const initialState = {
  currentAPI: '',
  showMenu: false,
  wazuhNotReadyYet: '',
  currentTab: '',
  extensions: {},
  selected_settings_section: '',
  currentPlatform: false,
  currentAgentData: JSON.parse(
    window.sessionStorage.getItem('wz-shared-selected-agent') || '{}',
  ),
  showExploreAgentModal: false,
  showExploreAgentModalGlobal: false,
  userPermissions: false,
  userRoles: [],
  toastNotification: false,
  withUserLogged: false,
  allowedAgents: [],
  logtestToken: '',
};
// ....
 if (action.type === 'UPDATE_SELECTED_AGENT_DATA') {
    window.sessionStorage.setItem(
      'wz-shared-selected-agent',
      JSON.stringify(action.currentAgentData),
    );
    return {
      ...state,
      currentAgentData: action.currentAgentData,
    };
  }

Originally posted by @Desvelao in #83 (comment)

Originally posted by @Desvelao in #83 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
Archived in project
Development

No branches or pull requests

2 participants