Answer accepted by question author
Hello @Abhay Punjabi
I've to address all your concerns listed out in small question and answer format below, kindly go through them one by one.
Why are these storage accounts being flagged?
Storage accounts under SFC_*GUID* resource groups are automatically created by Service Fabric Managed Clusters for diagnostics and operations. Because they’re created dynamically, they don’t always inherit network restrictions by default, which triggers security alerts.
How can we secure them if we didn’t create them?
You can apply network controls after creation:
- Allow access only from the VNETs/subnets used by your Service Fabric cluster
or - Use Network Security Perimeters (NSPs) to manage access with service-tag-based rules.
Do we need to allow anything else? Yes. The storage accounts must still allow required access for diagnostics, logging, and operational recovery scenarios used by the cluster.
Can we use NSPs instead of VNET rules?
Yes. NSPs are supported and are a good alternative. You can start in Learning mode to avoid alerts, then move to Enforced mode after validating in non-production.
What should we test first? Before applying changes in production, confirm:
- No cluster warnings related to diagnostics
- Logs remain accessible
- Normal cluster operations continue
What about Service Fabric Managed Clusters (SFMC)? For SFMC, you can associate the storage account directly with your NSP. Once configured, the linkage happens automatically.
-
Abhay Punjabi 20 Reputation points • Microsoft Employee
Hey Ankit Yadav, we have a number of SFCs deployed across multiple subscriptions in multiple regions and multiple clouds, is there any other way to enable NSPs during creation? We would have to manually go to each SFC and enable an NSP, is there any solution involving an ARM template or a configuration that would mitigate this?
-
Ankit Yadav 14,455 Reputation points • Microsoft External Staff • Moderator
Yes, you can use below ARM template to create NSP:-
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "networkSecurityPerimeterName": { "type": "string", "metadata": { "description": "The name of the NSP." } }, "profileName": { "type": "string", "defaultValue": "defaultProfile", "metadata": { "description": "The name of the NSP Profile." } }, "nspLocation": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "The location in which the NSP resource will be deployed." } } }, "variables": {}, "resources": [ { "type": "Microsoft.Network/networkSecurityPerimeters", "apiVersion": "2023-08-01-preview", "name": "[parameters('networkSecurityPerimeterName')]", "location": "[parameters('nspLocation')]", "properties": {} }, { "type": "Microsoft.Network/networkSecurityPerimeters/profiles", "apiVersion": "2023-08-01-preview", "name": "[format('{0}/{1}', parameters('networkSecurityPerimeterName'), parameters('profileName'))]", "location": "[parameters('nspLocation')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityPerimeters', parameters('networkSecurityPerimeterName'))]" ], "properties": {} } ] }and the parameters for it are as follows:-
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "networkSecurityPerimeterName": { "value": "" }, "profileName": { "value": "" }, "nspLocation": { "value": "" } } }Once created, you can use something like below to associate NSP with your resources:-
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "networkSecurityPerimeterName": { "type": "string", "metadata": { "description": "The name of the NSP." } }, "profileName": { "type": "string", "defaultValue": "defaultProfile", "metadata": { "description": "The name of the NSP Profile." } }, "passResourceId": { "type": "string", "metadata": { "description": "The resource id of the resource to associate." } }, "resourceAssociationName": { "type": "string", "defaultValue": "[concat('association-', substring(parameters('passResourceId'), add(lastIndexOf(parameters('passResourceId'), '/'), 1)))]", "metadata": { "description": "The name of the association corresponding to resource." } }, "associationMode": { "type": "string", "defaultValue": "Learning", "metadata": { "description": "The association mode." } } }, "variables": {}, "resources": [ { "type": "Microsoft.Network/networkSecurityPerimeters/resourceAssociations", "apiVersion": "2023-08-01-preview", "name": "[concat(parameters('networkSecurityPerimeterName'), '/', parameters('resourceAssociationName'))]", "properties": { "privateLinkResource": { "id": "[parameters('passResourceId')]" }, "profile": { "id": "[resourceId('Microsoft.Network/networkSecurityPerimeters/profiles', parameters('networkSecurityPerimeterName'), parameters('profileName'))]" }, "accessMode": "[parameters('associationMode')]" } } ] }Parameters for this template can be made using below:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "networkSecurityPerimeterName": { "value": "" }, "profileName": { "value": "" }, "passResourceId": { "value": "" }, "resourceAssociationName": { "value": "" }, "associationMode": { "value": "" } } }In a resource like the NSP (e.g.,
Microsoft.Network/networkSecurityPerimeters), set thetagsproperty conditionally. Merge with existing tags if needed:"tags": { "Environment": "[parameters('environment')]", "[if(parameters('createTag'), json('{\"tag1\": \"value1\",\"tag2\":\"value2\"}'), json('{}'))]": {} }
Sign in to comment
