Skip to main content
emnode
Compliance High severity MCSB DP-3

Microsoft Defender for Cloud · Service Fabric

Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign

Written and reviewed by Emnode · Last reviewed

What does the recommendation "Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign" check?

Flags any Microsoft.ServiceFabric/clusters resource where the ClusterProtectionLevel parameter, held in the Security section of the cluster's fabricSettings, is not set to EncryptAndSign. That setting governs how the nodes inside one cluster talk to each other: EncryptAndSign means every node-to-node message is both encrypted and digitally signed using the primary cluster certificate, while the weaker Sign and None values leave that intra-cluster traffic readable or unauthenticated. The control only inspects this internal transport level. It does not check client-to-node authentication, the reverse proxy, application-level TLS for your own services, or the certificate's expiry, and it does not apply to Service Fabric managed clusters, which always encrypt and sign node traffic and expose no equivalent toggle.

Why does "Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign" matter?

The nodes in a Service Fabric cluster constantly exchange the system's most sensitive internal state: replication of stateful service data, cluster secrets, configuration and orchestration messages. With ClusterProtectionLevel at None or Sign, an attacker who reaches the cluster's virtual network, or a compromised node, can read that traffic in the clear or, with None, inject forged messages that the federation will trust. The practical consequence is loss of confidentiality for any data your services replicate and a credible path to manipulating cluster behaviour from inside the subnet. EncryptAndSign closes both gaps and is the secure default Microsoft ships, so a cluster running anything lower is almost always an oversight that should be corrected before it holds production data.

How do I fix "Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign"?

  1. In the cluster's ARM or Bicep definition, set the Security fabric setting so the parameter named ClusterProtectionLevel has value EncryptAndSign: fabricSettings: [ { name: 'Security', parameters: [ { name: 'ClusterProtectionLevel', value: 'EncryptAndSign' } ] } ]. Deploy the updated template to apply it to the existing cluster, since this property has no dedicated az sf flag and is managed through the cluster resource definition.
  2. Confirm the change took effect by reading back the live value: az resource show --resource-group <rg> --resource-type Microsoft.ServiceFabric/clusters --name <cluster> --query "properties.fabricSettings". Check that the Security section reports ClusterProtectionLevel as EncryptAndSign across the cluster.
  3. Prevent regressions by assigning the built-in policy with the Deny effect so future clusters cannot deploy a weaker level. Look the definition up by name rather than pasting a GUID: pid=$(az policy definition list --query "[?displayName=='Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign'].name" -o tsv); az policy assignment create --name sf-encryptandsign --policy "$pid" --scope <scope> --params '{"effect":{"value":"Deny"}}'.

Remediation script · bash

# Close the highest-impact plaintext doors first: the Redis non-SSL port,
# then HTTPS-only + a modern TLS floor on every web app.

# Redis: disable the non-SSL port 6379 and require TLS 1.2 (clients use 6380).
for cache in $(az redis list --query "[?enableNonSslPort].name" -o tsv); do
  rg=$(az redis list --query "[?name=='$cache'].resourceGroup" -o tsv)
  az redis update --name "$cache" --resource-group "$rg" \
    --set enableNonSslPort=false minimumTlsVersion=1.2
  echo "$cache: non-SSL port disabled, min TLS 1.2"
done

# Web apps: enforce HTTPS only and raise the TLS floor.
for app in $(az webapp list --query "[?httpsOnly==\`false\`].name" -o tsv); do
  rg=$(az webapp list --query "[?name=='$app'].resourceGroup" -o tsv)
  az webapp update --name "$app" --resource-group "$rg" --https-only true
  az webapp config set --name "$app" --resource-group "$rg" --min-tls-version 1.2
  echo "$app: HTTPS only, min TLS 1.2"
done

# Functions follow the same pattern with az functionapp update --set httpsOnly=true.

# Ratchet it shut: assign the built-in deny policy for web apps over HTTPS only.
az policy assignment create \
  --name require-https-webapp \
  --policy a4af4a39-4135-47fb-b175-47fbdf85311d \
  --scope "/subscriptions/00000000-0000-0000-0000-000000000000"

Full walkthrough (console steps, edge cases and verification) in the lesson Enforce encryption in transit across Azure services.

Is "Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign" a false positive?

A throwaway development or test cluster deliberately created with ClusterProtectionLevel set to None to simplify local certificate handling will still flag, and correctly so by the control's definition. If that cluster never holds real or regulated data and lives in an isolated subscription, an explicit policy exemption scoped to it is a defensible exception, provided the exemption is documented and the cluster is barred from carrying production workloads.