Summary
Global Secure Access is rolling out multiple traffic forwarding profiles per traffic type as a private preview (two previews exercise the same mechanism: Multiple Forwarding Profiles for Private Access on private, and Fail-Close on internet). Migrate2GSA's export and provisioning cmdlets were written against the old assumption of exactly one forwarding profile per traffic type.
PR #82 fixes the immediate breakage — a false Private Access is not enabled error on preview tenants — but that only restores the on/off gate. This issue tracks the remaining coverage gaps.
Full analysis, proposed CSV shape, sized work breakdown, and blockers: docs/featureImprovements/mtfp-coverage-fixideas.md (added in the companion docs PR).
Gaps
-
Export loses profile topology. Export-EntraPrivateAccessConfig emits one CSV row per application segment with no representation of which forwarding profiles exist, their priority / state / clientFallbackAction, which apps belong to which profile, or per-profile user/group/device/platform assignment. An admin exporting a preview tenant gets a CSV that silently implies every app is reachable by every assigned user — exactly the assumption the preview breaks.
-
Provisioning cannot reproduce a preview tenant. Start-EntraPrivateAccessProvisioning has no concept of a forwarding profile, so a restore into a preview tenant collapses everything into the default profile. This is security-relevant: apps intended for a narrow custom profile become broadly reachable.
-
Internet Access export misses fail-close posture. Export-EntraInternetAccessConfig exports filtering policies and security profiles but no forwarding-profile data, so a clientFallbackAction: block profile is invisible in the export.
Proposed direction
Two artifacts, following the pattern Export-EntraInternetAccessConfig already uses for its separate Policies and SecurityProfiles CSVs:
{timestamp}_EPA_Config.csv — one new additive column, ForwardingProfiles (semicolon-separated profile names, same convention as EntraGroups). Existing CSVs keep importing unchanged.
{timestamp}_EPA_ForwardingProfiles.csv — new file carrying ProfileName, Priority, State, IsDefault, ClientFallbackAction, QuickAccessEnabled, AssignedGroups, AssignedUsers, DevicePlatforms, Provision.
Import side mirrors this with an optional -ForwardingProfileConfigPath parameter; absent means today's behaviour exactly.
Recommended split
- A — unblocked. Export every PA and IA forwarding profile plus metadata into the new profiles CSV. Leave
ForwardingProfiles blank on the app CSV and warn when more than one profile of a traffic type is detected. Makes the export honest without asserting membership the tool cannot determine. Small, low risk, no new Graph scopes.
- B — blocked. Profile→app membership, provisioning writes, and assignment round-trip. Gated on the blockers below. A wrong guess about the join model means rewriting the CSV contract, which is a breaking change for anyone who has adopted it.
Blockers — need preview product team input
- Profile→app join has no confirmed public surface.
forwardingRule carries no appId in the public schema, and private profiles may not expose policyRules at all. Without a confirmed Graph representation the membership column cannot be populated — and that is the most valuable part of the export.
associations is opaque. No @odata.type values or field names published for user/group/device/platform assignment, so assignment provisioning is unimplementable and the export can only round-trip a blob that will not survive a CSV.
- Write API unverified. Nothing confirms
POST/PATCH on /beta/networkAccess/forwardingProfiles is available in the preview, or whether profile creation is portal-only. If portal-only, the write slice collapses to "export only, document the manual step".
- Field details unconfirmed. Exact
clientFallbackAction name and casing; the default profile's priority sentinel (100? absent? null?) — needed to reliably distinguish default from custom.
- Scope requirements unknown. Whether
NetworkAccess.Read.All covers the expanded policies / associations reads, or whether the preview gates them behind an additional scope. Changes the consent story for the export.
Open questions
- Can a
private custom profile also set clientFallbackAction: block, or is fail-close exclusively an Internet Access scenario in this preview?
- Does the preview API expose an explicit app reference on PA forwarding profiles? If not, is destination-matching against application segments acceptable, or is a separate Graph call required?
- Should
Export-EntraPrivateAccessAppDiscovery become profile-aware, or is discovery inherently profile-agnostic?
- Does the default profile always contain every app, making it a reliable superset for validation during provisioning?
Summary
Global Secure Access is rolling out multiple traffic forwarding profiles per traffic type as a private preview (two previews exercise the same mechanism: Multiple Forwarding Profiles for Private Access on
private, and Fail-Close oninternet). Migrate2GSA's export and provisioning cmdlets were written against the old assumption of exactly one forwarding profile per traffic type.PR #82 fixes the immediate breakage — a false
Private Access is not enablederror on preview tenants — but that only restores the on/off gate. This issue tracks the remaining coverage gaps.Full analysis, proposed CSV shape, sized work breakdown, and blockers:
docs/featureImprovements/mtfp-coverage-fixideas.md(added in the companion docs PR).Gaps
Export loses profile topology.
Export-EntraPrivateAccessConfigemits one CSV row per application segment with no representation of which forwarding profiles exist, theirpriority/state/clientFallbackAction, which apps belong to which profile, or per-profile user/group/device/platform assignment. An admin exporting a preview tenant gets a CSV that silently implies every app is reachable by every assigned user — exactly the assumption the preview breaks.Provisioning cannot reproduce a preview tenant.
Start-EntraPrivateAccessProvisioninghas no concept of a forwarding profile, so a restore into a preview tenant collapses everything into the default profile. This is security-relevant: apps intended for a narrow custom profile become broadly reachable.Internet Access export misses fail-close posture.
Export-EntraInternetAccessConfigexports filtering policies and security profiles but no forwarding-profile data, so aclientFallbackAction: blockprofile is invisible in the export.Proposed direction
Two artifacts, following the pattern
Export-EntraInternetAccessConfigalready uses for its separate Policies and SecurityProfiles CSVs:{timestamp}_EPA_Config.csv— one new additive column,ForwardingProfiles(semicolon-separated profile names, same convention asEntraGroups). Existing CSVs keep importing unchanged.{timestamp}_EPA_ForwardingProfiles.csv— new file carryingProfileName,Priority,State,IsDefault,ClientFallbackAction,QuickAccessEnabled,AssignedGroups,AssignedUsers,DevicePlatforms,Provision.Import side mirrors this with an optional
-ForwardingProfileConfigPathparameter; absent means today's behaviour exactly.Recommended split
ForwardingProfilesblank on the app CSV and warn when more than one profile of a traffic type is detected. Makes the export honest without asserting membership the tool cannot determine. Small, low risk, no new Graph scopes.Blockers — need preview product team input
forwardingRulecarries noappIdin the public schema, andprivateprofiles may not exposepolicyRulesat all. Without a confirmed Graph representation the membership column cannot be populated — and that is the most valuable part of the export.associationsis opaque. No@odata.typevalues or field names published for user/group/device/platform assignment, so assignment provisioning is unimplementable and the export can only round-trip a blob that will not survive a CSV.POST/PATCHon/beta/networkAccess/forwardingProfilesis available in the preview, or whether profile creation is portal-only. If portal-only, the write slice collapses to "export only, document the manual step".clientFallbackActionname and casing; the default profile'sprioritysentinel (100? absent? null?) — needed to reliably distinguish default from custom.NetworkAccess.Read.Allcovers the expandedpolicies/associationsreads, or whether the preview gates them behind an additional scope. Changes the consent story for the export.Open questions
privatecustom profile also setclientFallbackAction: block, or is fail-close exclusively an Internet Access scenario in this preview?Export-EntraPrivateAccessAppDiscoverybecome profile-aware, or is discovery inherently profile-agnostic?