Security Considerations
permalink: customerhostedsecurityconsiderations
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 |
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
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:
- Open each of the following storage accounts in turn and follow the below steps:
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
- In the Azure Portal, open API Management > Certificates (in the left-hand menu).
- Click + Add.
- Upload the .pfx file, and provide its password.
- 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
- Go to your API (apolloapi) in APIM.
- Ensure the "apolloapi" menu item is selected
- Under Backend, click the edit button
- Choose the certificate you just uploaded (
apim-client-cert). - Save
Configure the Function App to Require Client Certificates
- Enforce HTTPS Only
- In the Azure portal, go to your Function App > Configuration > General settings.
- Ensure HTTPS Only is set to On (best practice for security).
- Require Client Certificates (mTLS)
- Still under your Function App’s Configuration (or “TLS/SSL settings” in some portal versions), find Client Certificate Mode.
- Change it to Require (or On).
- 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.