Skip to content

Security Considerations


Introduction

This document outlines all the security considerations when hosting the ProcessFactorial product on a customer site via the Customer Hosted Model

This includes existing default security features, additional strongly recommended security features and optional features

Also see [[{DRAFT}Sequence Diagrams]]

General

The default deployment of the ProcessFactorial within the Customer Hosted Model does not create virtual networks. It is recommended that all components that is not internet facing, be placed in a virtual network.

Recommendations

Portal

Security Consideration Recomendation Components Action Comment
TLS Version - Minimum version 1.3 Optional NPO Portal (npobp_portal)
Portal Backend (npobp_portalbackend)
Manual Currently version 1.2 is used because APIM does not support 1.3 yet, even though the function apps do. Once APIM offers this support, upgrade to 1.3
IP Address / Virtual Network Access NPO Portal (npobp_portal)
Portal Backend (npobp_portalbackend)
Manual Recommendation TBC
Diagnostic logs in App Service should be enabled Optional NPO Portal (npobp_portal)
Portal Backend (npobp_portalbackend)
Manual Useful in diagnostics only. Not a direct security concern
Managed identity should be used in web apps NPO Portal (npobp_portal)
Portal Backend (npobp_portalbackend)
Manual Recommendation TBC
CORS should not allow every resource to access Web Applications Mandatory NPO Portal (npobp_portal)
Portal Backend (npobp_portalbackend)
Manual For NPO Portal (npobp_portal), the CORS origin should be limited to the source portal itself

For Portal Backend (npobp_portalbackend), the CORS origin should only allow the NPO Portal (npobp_portal) URLs
### Function Apps
Security Consideration Recomendation Components Action Comment
TLS Version - Minimum version 1.3 Optional Custom Functions Function App (npobp_common)
Config Function App (npobp_config)
Execution Engine (npobp_exec)
Master Maintenance Service (npobp_mastmaint)
Polling Engine (npobp_poll)
Translation Layer - Dataverse (npobp_trdataverse)
Translation Layer SQL (npobp_trsql)
Translation Layer SFDC (npobp_trsfdc)
Automatic Currently version 1.2 is used because APIM does not support 1.3 yet, even though the function apps do. Once APIM offers this support, upgrade to 1.3
Function apps should have Client Certificates (Incoming client certificates) enabled Recommended Custom Functions Function App (npobp_common)
Config Function App (npobp_config)
Execution Engine (npobp_exec)
Master Maintenance Service (npobp_mastmaint)
Polling Engine (npobp_poll)
Translation Layer - Dataverse (npobp_trdataverse)
Translation Layer SQL (npobp_trsql)
Translation Layer SFDC (npobp_trsfdc)
Manual Limits access to each app to clients with valid certificate.

npobp_common may be accessible via the Customer Portal, so additional care must be given
CORS Mandatory Custom Functions Function App (npobp_common)
Config Function App (npobp_config)
Execution Engine (npobp_exec)
Master Maintenance Service (npobp_mastmaint)
Polling Engine (npobp_poll)
Translation Layer - Dataverse (npobp_trdataverse)
Translation Layer SQL (npobp_trsql)
Translation Layer SFDC (npobp_trsfdc)
Manual Only the Custom Functions Function App (npobp_common) app can ever be accessed directly. CORS should be limited to the ProcessFactorial Portal and the Customer Portal

Only the npobp_config app will ever be accessed indirectly via APIM and APIM will manage the CORS.

All translation apps (Translation Layer - Dataverse (npobp_trdataverse), Translation Layer SQL (npobp_trsql), etc.) will only ever be accessed directly via Config Function App (npobp_config), Execution Engine (npobp_exec) and Polling Engine (npobp_poll)

Polling apps (Polling Engine (npobp_poll) and Master Maintenance Service (npobp_mastmaint)) and execution app (Execution Engine (npobp_exec)) will never be accessed outside of the apps.
### APIM
The default installation of APIM will not come with any mandatory security policies. All user authorisation happens within the app itself. This includes, amongst others, JWT validation in the same manner that the APIM policies would have done this.

For the Customer Hosted Model, we recommend the additional APIM policies below. However, care should be given that they do not clash with the existing security checks within the app.

Channels

APIM will be the only egress point into the backend services. APIM can be accessed via the following channels. In each case, the back end of the APIM instance is always the config app (Config Function App (npobp_config))

Channel Comment
ProcessFactorial Portal All configuration done by configurators and administrators will be routed via APIM. Two APIs are generally consumed (apolloapi and testharnessapi). The latter is used to host a Test Factorial Form on the ProcessFactorial Portal
Customer Portal For Factorial Form forms from the Customer Portal, all interactions will go through APIM. This is via a separate API and should be secured accordingly
Master Maintenance App This app does platform based metric rollups. Most Customer Hosted Model instances will not use this feature unless they host multiple customers as a reseller
#### Recommendations
Security Consideration Recomendation
-------------------------------------------------------- -------------
CORS - Limit Origin Mandatory
IP Filter - Limit IP Addresses Optional
Validate JWT - Validate the JWT token sent by the client Recommended

Storage

Azure Storage Accounts

Security Consideration Recomendation Components Action Comment
Access Level (Container) - Private Mandatory Data Store - Configuration (npobp_custconfig)
Data Store - Master (npobp_mast)
Data Store - Master Reporting (npobp_mastrep)
Data Store - Execution (npobp_custexec)
Data Store - Reporting (npobp_custrep)
Automatic
Storage account should use a private link connection Recommended Data Store - Configuration (npobp_custconfig)
Data Store - Master (npobp_mast)
Data Store - Master Reporting (npobp_mastrep)
Data Store - Execution (npobp_custexec)
Data Store - Reporting (npobp_custrep)
Manual #Private Endpoints
Storage accounts should restrict network access using virtual network rules Recommended Data Store - Configuration (npobp_custconfig)
Data Store - Master (npobp_mast)
Data Store - Master Reporting (npobp_mastrep)
Data Store - Execution (npobp_custexec)
Data Store - Reporting (npobp_custrep)
Manual #Private Endpoints
Storage accounts should prevent shared key access Recommended Data Store - Configuration (npobp_custconfig)
Data Store - Master (npobp_mast)
Data Store - Master Reporting (npobp_mastrep)
Data Store - Execution (npobp_custexec)
Data Store - Reporting (npobp_custrep)
Manual Recommendation TBC

MongoDB (Cosmos)

Security Consideration Recomendation Components Action Comment
CosmosDB accounts should use private link Recommended Data Store - Configuration (npobp_custconfig)
Data Store - Master (npobp_mast)
Data Store - Master Reporting (npobp_mastrep)
Data Store - Execution (npobp_custexec)
Data Store - Reporting (npobp_custrep)
Manual #Private Endpoints
Azure Cosmos DB accounts should have firewall rules Recommended Data Store - Configuration (npobp_custconfig)
Data Store - Master (npobp_mast)
Data Store - Master Reporting (npobp_mastrep)
Data Store - Execution (npobp_custexec)
Data Store - Reporting (npobp_custrep)
Manual #MongoDB
Azure Cosmos DB should disable public network access Recommended Data Store - Configuration (npobp_custconfig)
Data Store - Master (npobp_mast)
Data Store - Master Reporting (npobp_mastrep)
Data Store - Execution (npobp_custexec)
Data Store - Reporting (npobp_custrep)
Manual #MongoDB
### KeyVault

The ProcessFactorial KeyVault should only be used for managing secrets within the ProcessFactorial It should not be used for additional infrastructure secrets such as client certificates. A separate managed KeyVault should be used

Security Consideration Recomendation Components Action Comment
Key vaults should have purge protection enabled Recommended KeyVault (npobp_keyvault) Manual Recommended to prevent data loss due to accidental deletion. Not a direct security concern
Azure Key Vaults should use private link Recommended KeyVault (npobp_keyvault) Manual #KeyVault
Firewall should be enabled on Key Vault Recommended KeyVault (npobp_keyvault) Manual #KeyVault
Diagnostic logs in Key Vault should be enabled Optional KeyVault (npobp_keyvault) Manual Useful in diagnostics only. Not a direct security concern
### Service Bus
Security Consideration Recomendation Components Action Comment
------------------------------------------------ ------------- ----------------- ------ ---------------------------------------------------------
Diagnostic logs in Service Bus should be enabled Optional Execution Service Bus (npobp_execbus) Manual Useful in diagnostics only. Not a direct security concern

Virtual Network (VNets)

Component SKUs

Not all the Azure SKUs and Tiers have the ability to add to a VNet. If, VNets are required, ensure the following minimum SKU and Tier values in the customerconfig.json If using the deployment script to update these values, make sure you delete the App Service Plan from Azure first, then run the script. This will recreate the App Service Plan and the Function Apps within it.

The below is the minimum Azure SKU and Tiers required. Note that these are paid services on Azure.

identifier initialSkuName initialTier
servicePlanPython B1 Basic
servicePlanDotNetConfig B1 Basic
servicePlanNodeJS B1 Basic
servicePlanDotNetExec B1 Basic
apim Developer
### Subnets

It is recommended that subnets be created within the VNet to further limit access and distribute risk. We recommend that the following subnets be created via the script if you wish to subdivide the deployment into subnets.

subnet name purpose Address Suffix
subnet01portal Contains the portal components 27
subnet02config Contains the configuration function apps 27
subnet03exec Contains the execution engine function apps 27
subnet04python Contains the common functions function app 27
~~subnet05db~~ ~~Contains the storage accounts and mongodb accounts~~ ~~28~~
~~subnet06kv~~ ~~Contains keyvault~~ ~~28~~
subnet07apim APIM network addresses 28
### Components and Subnet Allocation
Type Components Subnets Comment
Transactional
Storage Accounts
Data Store - Configuration (npobp_custconfig)
Data Store - Master (npobp_mast)
Data Store - Execution (npobp_custexec)
Data Store - Reporting (npobp_custrep)
Data Store - Master Reporting (npobp_mastrep) (only if installed)
subnet02config
subnet03exec
~~subnet05db~~
Config and Execution function apps need access to the storage accounts
Transactional
MongoDB
Data Store - Execution (npobp_custexec)
Data Store - Reporting (npobp_custrep)
subnet02config
subnet03exec
~~subnet05db~~
Config and Execution function apps need access to the storage accounts
Function App
Storage Account
Data Store - App Data - Execution Engine (npobp_execappdata) subnet03exec Used to store the function app artifacts.
Out of the box storage account
Function App
Storage Account
Data Store - App Data - Config (npobp_coreappdata) subnet02config Used to store the function app artifacts.
Out of the box storage account
App Service Plan
Portal
NPO Portal (npobp_portal)
Portal Backend (npobp_portalbackend)
subnet01portal Hosts the external facing portal.
This needs to be accessible by external users
App Service Plan
Config
Config Function App (npobp_config)
Master Maintenance Service (npobp_mastmaint)
subnet02config
~~subnet05db~~
~~subnet06kv~~
Hosts all the function apps related to configuration
Ensure Content Storage and Backup/Restore is selected on the subnet
App Service Plan
Config (Translation)
Translation Layer - Dataverse (npobp_trdataverse)
Translation Layer SQL (npobp_trsql)
subnet02config
~~subnet05db~~
Used to translate between Process Factorial and target Data Store
Ensure Content Storage and Backup/Restore is selected on the subnet
App Service Plan
Execution Engine
Polling Engine (npobp_poll)
Execution Engine (npobp_exec)
subnet02config
subnet03exec
~~subnet05db~~
~~subnet06kv~~
Hosts all the function apps related to execution
Ensure Content Storage and Backup/Restore is selected on the subnet
App Service Plan
Common Functions
Custom Functions Function App (npobp_common) subnet04python Hosts all the function apps related to custom functions
Key Vault KeyVault (npobp_keyvault) subnet02config
subnet03exec
~~subnet06kv~~
Holds all the key vault secrets.
Only the configuration and execution processes should have access to it.
The portal and common functions should never have access to the key vault
APIM APIM (npobp_apim) subnetapim07
Service Bus Execution Service Bus (npobp_execbus) subnet02config
subnet03exec
Polling Engine and Config will write to the Service Bus
Execution Engine will listen to the Service Bus
App Insights App Insights (npobp_appinsightsmaster)
(App Insights - Execution (npobp_appinsightsexec)
With the setup in the table above, only the following Network Security Groups (NGS) needs to be created:
-

Storage Account Configuration

For storage accounts, once they are in a subnet, the script will no longer have access to them unless the script is run from a VM within the subnet. This means that each storage account needs to have your local IP address added to the VNet:

  1. Open each of the following storage accounts in turn and follow the below steps:
    1. Data Store - Master (npobp_mast)
    2. Data Store - Configuration (npobp_custconfig)
    3. Data Store - Execution (npobp_custexec)
    4. Data Store - Reporting (npobp_custrep)
    5. Data Store - Master Reporting (npobp_mastrep) (if installed) 6.

Additional Protections

SQL Injection Protections

All ProcessFactorial interactions with the customer Data Store are transformed into proprietary connection messages, which are then passed through one of our controlled connectors. This architecture introduces multiple layers between user input and the final CRUD operations, significantly reducing exposure to injection vectors.

When performing CRUD operations, native SDKs (such as the Dataverse SDK, Salesforce SDK, etc.) are used where available, leveraging their built-in security features. For direct SQL interactions — regardless of the underlying SQL engine — all queries are sanitized and fully parameterized, eliminating the risk of SQL injection attacks.

Cross-Site Request Forgery (CSRF)

ProcessFactorial does not rely on cookies for authentication or session management. All API requests are explicitly authenticated using a JWT token provided in the Authorization header. These tokens are validated on the server side for every request.

Since browsers do not automatically include headers like Authorization, our architecture is not vulnerable to CSRF attacks, which rely on the implicit inclusion of cookies in cross-origin requests.

Further Steps

Below are steps that can be followed to meet specific security recommendations. These are a guide only and NPO Factorial recommends that additional due diligence be taken.

Client Certificates

Client Certificates are useful in securing a given Azure Component and preventing access from a client that is not explicitly known to it.

Rotation and Expiry

Client certificates expire periodically and needs to be rotated. If the certificate expires prior to rotation, it will prevent the components from communicating with each other and will result in downtime. Always ensure certificates are rotated well in advance of expiry

Generating a Certificate

The instructions below show how to create a self-signed certificate for testing only. It is recommended that a trusted certificate authority (CA) be used to generate the certificate.

Run the below PowerShell script. The output will be a pfx file.

# Prompt user for input
$friendlyName = Read-Host -Prompt "Enter a friendly name for the certificate (e.g. APIM Client Cert)"
$subjectName  = Read-Host -Prompt "Enter the certificate subject name (CN) (e.g. apim-client)"

# Prompt for file path, defaulting to the current folder if user leaves it blank
Write-Host "Enter the output path for the .pfx file (default: current folder)."
$filePathInput = Read-Host -Prompt "Output path (e.g. C:\temp\apim-client.pfx)"
if ([string]::IsNullOrWhiteSpace($filePathInput)) {
    # Default to 'apim-client.pfx' in the current directory
    $filePathInput = Join-Path (Get-Location) "apim-client.pfx"
}
$filePath = $filePathInput

# Prompt for secure password
$certPassword = Read-Host -Prompt "Enter a password to secure the .pfx file" -AsSecureString

# Create the self-signed certificate
$cert = New-SelfSignedCertificate `
    -Subject "CN=$subjectName" `
    -CertStoreLocation "Cert:\CurrentUser\My" `
    -KeyExportPolicy Exportable `
    -FriendlyName $friendlyName

# Export the certificate as a PFX file
Export-PfxCertificate `
    -FilePath $filePath `
    -Password $certPassword `
    -Cert $cert

Write-Host "Certificate created and exported to: $filePath"

Upload Certificate

The certificate can either be uploaded to KeyVault or directly to the Azure component. This example will show how to upload it directly to APIM (npobp_apim) (apolloapi) as the client and Config Function App (npobp_config) as the target app. the same steps can be followed for other components based on the requirements in the tables above

Add the Certificate in APIM
  1. In the Azure Portal, open API Management > Certificates (in the left-hand menu).
  2. Click + Add.
  3. Upload the .pfx file, and provide its password.
  4. Give it a clear Name (e.g., apim-client-cert).

This makes the certificate available for APIM to use when calling backends.

Reference the Certificate in Your API / Backend
  1. Go to your API (apolloapi) in APIM.
  2. Ensure the "apolloapi" menu item is selected
  3. Under Backend, click the edit button
  4. Choose the certificate you just uploaded (apim-client-cert).
  5. Save
Configure the Function App to Require Client Certificates
  1. Enforce HTTPS Only
    1. In the Azure portal, go to your Function App > Configuration > General settings.
    2. Ensure HTTPS Only is set to On (best practice for security).
  2. Require Client Certificates (mTLS)
    1. Still under your Function App’s Configuration (or “TLS/SSL settings” in some portal versions), find Client Certificate Mode.
    2. Change it to Require (or On).
    3. Save your changes.

Note: With a self-signed cert, you’ll also need to ensure the Function App trusts that cert’s chain:

  • In TLS/SSL settings, under “Client Certificate”, you may upload your root certificate (the self-signed root or intermediate CA) as a trusted root.