Store ASP.NET Core Data Protection Keys Externally
1. Overview¶
ASP.NET Core encrypts and decrypts protected data, such as authentication cookies and CSRF tokens, with a mechanism called Data Protection.
By default, Data Protection keeps the data protection keys locally on each instance. In this case, when multiple instances run in a cluster configuration, an authentication cookie issued by one instance cannot be decrypted by another instance. You need to store the data protection keys in an external location that can be shared, so that all instances can refer to them.
With the AspNetCoreDataProtection parameter of Security.json, you can specify the storage location of the ASP.NET Core data protection keys. The data protection keys are XML data used to encrypt authentication cookies, CSRF tokens, and other protected data.
The storage locations (persistence destinations) of the data protection keys that you can specify are as follows. The storage locations that you can specify differ depending on the version of Pleasanter.
| Storage Location | Supported Versions |
|---|---|
| Azure (Blob Storage + Key Vault) | 1.3.21.0 and later |
| Database (Sessions table) | 1.3.21.0 and later |
| KVS | 1.5.7.0 and later |
Note: Azure Blob Storage is the storage location of the data protection keys.
Note: Azure Key Vault is the storage location of the encryption key that protects the data protection keys.
1-1. List of Parameters¶
The AspNetCoreDataProtection parameter of Security.json has the following parameters. Setting examples of each parameter are described later.
- The parameters that must be specified differ for each storage location.
- If the storage location is the database (Sessions table) and the parameters are omitted, fixed strings set automatically by the system are applied.
| Parameter Name | Description | Azure | KVS | DB |
|---|---|---|---|---|
| BlobContainerUri | The container URL of the data protection keys stored in Azure Blob Storage. | ✓ | ||
| KeyIdentifier | The URL of the encryption key stored in Azure Key Vault. | ✓ | ||
| KeyFileName | The file name of the data protection keys stored in Azure Blob Storage. | ✓ | ||
| XmlAesKey | The key material for encrypting the data protection keys with AES. | ✓ | (✓) | |
| KeyValueStoreConnectionString | The KVS connection string. | ✓ | ||
| KeyValueStoreKeyName | The name of the data protection keys stored in KVS. | ✓ |
1-2. How the Storage Location of the Data Protection Keys Is Determined (Priority)¶
The storage location of the data protection keys is determined when Pleasanter starts, based on the following priority. If Azure is specified as the storage location, Azure takes precedence even if KVS is also specified.
| Priority | Condition | Storage Location |
|---|---|---|
| 1 | BlobContainerUri and KeyIdentifier are set | Azure Blob Storage + Key Vault |
| 2 | The above are not set and KeyValueStoreConnectionString is set | KVS |
| 3 | None of the above are set | Database (Sessions table) |
1-3. Encryption of the Data Protection Keys¶
When Azure or KVS is specified as the storage location, the data protection keys are stored externally, so they are encrypted with AES. For AES encryption, the XmlAesKey parameter of Security.json is used as the AES key material. Therefore, XmlAesKey must be set when Azure or KVS is specified as the storage location.
When the database (Sessions table) is used as the storage location, the service name (the value of the Name parameter of Service.json) is used as the default AES key material (when XmlAesKey is null).
1-4. File Name of the Data Protection Keys¶
The file name of the data protection keys is specified with the following parameters.
| Storage Location | Parameter | Example |
|---|---|---|
| Azure Blob Storage | KeyFileName | "keys.xml" |
| KVS | KeyValueStoreKeyName | "Pleasanter-Prod:DataProtection-Keys" |
If KeyValueStoreKeyName is omitted, a file name is assigned implicitly based on the following rule.
For example, if the service name is Implem.Pleasanter, the default file name is Implem.Pleasanter:DataProtection-Keys. When multiple environments share one KVS, you can prevent key ring conflicts by using a different KeyValueStoreKeyName for each environment.
1-5. About ASP.NET Core Data Protection¶
For details of ASP.NET Core data protection, refer to the following Microsoft documents.
- Configure ASP.NET Core Data Protection
- Data Protection key management and lifetime in ASP.NET Core
- Key storage providers in ASP.NET Core
2. Prerequisites¶
The prerequisites for storing the data protection keys in KVS are as follows.
- When storing the data protection keys in KVS, enable KVS persistence (AOF or RDB). If KVS is restarted with persistence disabled, the data protection keys are lost. If the data protection keys are lost, existing authentication cookies, CSRF tokens, and protected data cannot be decrypted, and users are affected, for example by having to log in again.
- To prevent the data protection keys from being stored in KVS in plain text by mistake, be sure to specify the XmlAesKey parameter of Security.json. If you enable storage in KVS without specifying XmlAesKey, Pleasanter results in an error and does not start.
- When multiple instances share the data protection keys, the KeyValueStoreConnectionString and XmlAesKey parameters of "Security.json" and the service name (application name) must be the same across the instances.
- When multiple environments share one KVS, use a different KeyValueStoreKeyName parameter of "Security.json" for each environment to prevent conflicts of the data protection keys.
3. Setting Examples (Settings in the Parameter File)¶
3-1. Specifying Azure as the Storage Location of the Data Protection Keys¶
Security.json¶
"AspNetCoreDataProtection": {
"BlobContainerUri": "https://stragename.blob.core.windows.net/containername",
"KeyIdentifier": "https://keyvalult-name.vault.azure.net/keys/key-name/...",
"KeyFileName": "Keys.xml",
"XmlAesKey":null,
"KeyValueStoreConnectionString":null,
"KeyValueStoreKeyName": null
},
| Parameter | Notes |
|---|---|
| BlobContainerUri KeyIdentifier | These parameters are required when Azure is specified as the storage location. |
3-2. Specifying KVS as the Storage Location of the Data Protection Keys¶
Security.json¶
"AspNetCoreDataProtection": {
"BlobContainerUri": null,
"KeyIdentifier": null,
"KeyFileName": null,
"XmlAesKey": "a0b1c2...",
"KeyValueStoreConnectionString": "localhost:6379,abortConnect=false",
"KeyValueStoreKeyName": "Pleasanter:DataProtection-Keys"
},
| Parameter | Notes |
|---|---|
| XmlAesKey | In a cluster environment, specify the same string for all Pleasanter instances. |
| KeyValueStoreConnectionString | Be sure to add abortConnect=false to the end of the connection string. If Pleasanter cannot connect to KVS, it may fail to start (for example, the default of StackExchange.Redis is abortConnect=true). With abortConnect=false, Pleasanter continues to start even if KVS is temporarily unreachable at startup, and the connection is retried in the background. In a cluster environment, specify the same string for all Pleasanter instances. |
In a cluster environment, in addition to the notes above, you need to specify the same string for the service name.
3-3. Sharing One KVS among Multiple Environments¶
Use a different KeyValueStoreKeyName for each environment to prevent key ring conflicts.
Security.json (Production Environment)¶
"AspNetCoreDataProtection": {
: omitted
"KeyValueStoreConnectionString": "redis.example.com:6379,abortConnect=false",
"KeyValueStoreKeyName": "Pleasanter-Prod:DataProtection-Keys"
},
Security.json (Staging Environment)¶
"AspNetCoreDataProtection": {
: omitted
"KeyValueStoreConnectionString": "redis.example.com:6379,abortConnect=false",
"KeyValueStoreKeyName": "Pleasanter-Stg:DataProtection-Keys"
},
3-4. Specifying the Database (Sessions Table) as the Storage Location of the Data Protection Keys¶
When you specify the database (Sessions table) as the storage location of the data protection keys, you do not need to edit Security.json.
Security.json (Default Settings)¶
"AspNetCoreDataProtection": {
"BlobContainerUri": null,
"KeyIdentifier": null,
"KeyFileName": "Keys.xml",
"XmlAesKey": null,
"KeyValueStoreConnectionString": null,
"KeyValueStoreKeyName": null
},
4. How to Register in System Environment Variables¶
The values of the following parameters can be registered in system environment variables.
- BlobContainerUri
- KeyIdentifier
- XmlAesKey
- KeyValueStoreConnectionString
- KeyValueStoreKeyName
For registering in system environment variables, also check the following page.
"Parameter Settings: Register Credentials in System Environment Variables"
4-1. Naming Rules¶
The naming rules of the system environment variables are as follows.
(service name)_Security_AspNetCoreDataProtection_BlobContainerUri
(service name)_Security_AspNetCoreDataProtection_KeyIdentifier
(service name)_Security_AspNetCoreDataProtection_XmlAesKey
(service name)_Security_AspNetCoreDataProtection_KeyValueStoreConnectionString
(service name)_Security_AspNetCoreDataProtection_KeyValueStoreKeyName
| Item | Required | Description |
|---|---|---|
| Service name | Yes | Specify the value of EnvironmentName or Name of Service.json |
4-1-1. Setting Examples¶
| Variable | Example |
|---|---|
| Implem.Pleasanter_Security_AspNetCoreDataProtection_BlobContainerUri | https://stragename.blob.core.windows.net/containername |
| Implem.Pleasanter_Security_AspNetCoreDataProtection_KeyIdentifier | https://keyvalult-name.vault.azure.net/keys/key-name/.... |
| Implem.Pleasanter_Security_AspNetCoreDataProtection_XmlAesKey | a0b1c2... |
| Implem.Pleasanter_Security_AspNetCoreDataProtection_KeyValueStoreConnectionString | redis.example.com:6379,abortConnect=false |
| Implem.Pleasanter_Security_AspNetCoreDataProtection_KeyValueStoreKeyName | Pleasanter-Stg:DataProtection-Keys |
4-2. Order of Precedence¶
The order of precedence when values are set in both this parameter file and the system environment variables, or when they are set in an abbreviated form, is as follows.
4-2-1. Order of Precedence for BlobContainerUri¶
| Order | Value |
|---|---|
| 1 | "BlobContainerUri" in this parameter file |
| 2 | "(service name: EnvironmentName)_Security_AspNetCoreDataProtection_BlobContainerUri" in the environment variables |
| 3 | "(service name: Name)_Security_AspNetCoreDataProtection_BlobContainerUri" in the environment variables |
4-2-2. Order of Precedence for KeyIdentifier¶
| Order | Value |
|---|---|
| 1 | "KeyIdentifier" in this parameter file |
| 2 | "(service name: EnvironmentName)_Security_AspNetCoreDataProtection_KeyIdentifier" in the environment variables |
| 3 | "(service name: Name)_Security_AspNetCoreDataProtection_KeyIdentifier" in the environment variables |
4-2-3. Order of Precedence for XmlAesKey¶
| Order | Value |
|---|---|
| 1 | "KeyIdentifier" in this parameter file |
| 2 | "(service name: EnvironmentName)_Security_AspNetCoreDataProtection_XmlAesKey" in the environment variables |
| 3 | "(service name: Name)_Security_AspNetCoreDataProtection_XmlAesKey" in the environment variables |
4-2-4. Order of Precedence for KeyValueStoreConnectionString¶
| Order | Value |
|---|---|
| 1 | "KeyIdentifier" in this parameter file |
| 2 | "(service name: EnvironmentName)_Security_AspNetCoreDataProtection_KeyValueStoreConnectionString" in the environment variables |
| 3 | "(service name: Name)_Security_AspNetCoreDataProtection_KeyValueStoreConnectionString" in the environment variables |
4-2-5. Order of Precedence for KeyValueStoreKeyName¶
| Order | Value |
|---|---|
| 1 | "KeyIdentifier" in this parameter file |
| 2 | "(service name: EnvironmentName)_Security_AspNetCoreDataProtection_KeyValueStoreKeyName" in the environment variables |
| 3 | "(service name: Name)_Security_AspNetCoreDataProtection_KeyValueStoreKeyName" in the environment variables |
4-3. Notes on Registering in System Environment Variables¶
As described in "2. Order of Precedence", the value set in the parameter file has the highest priority. Therefore, when you register values in system environment variables, specify "null" in the parameter file.
5. Supported Versions¶
| Supported versions | Body |
|---|---|
| 1.3.21.0 and later | Added function |
| 1.5.7.0 and later | Added the following parameters - KeyValueStoreConnectionString - KeyValueStoreKeyName |