diff --git a/client-react/src/models/site/site.ts b/client-react/src/models/site/site.ts index 9a696a714b..ccc686e675 100644 --- a/client-react/src/models/site/site.ts +++ b/client-react/src/models/site/site.ts @@ -164,6 +164,7 @@ export interface Site { sshEnabled?: boolean | null; endToEndEncryptionEnabled?: boolean; functionAppConfig?: FunctionAppConfig; + functionsRuntimeAdminIsolationEnabled?: boolean; } export interface HostNameSslState { diff --git a/client-react/src/pages/app/app-settings/AppSettingsDataLoader.tsx b/client-react/src/pages/app/app-settings/AppSettingsDataLoader.tsx index 89fc1854e8..f1af9fb21a 100644 --- a/client-react/src/pages/app/app-settings/AppSettingsDataLoader.tsx +++ b/client-react/src/pages/app/app-settings/AppSettingsDataLoader.tsx @@ -164,7 +164,8 @@ const AppSettingsDataLoader: React.FC = props => { if (isFunctionApp(site.data)) { const os = isLinux ? AppStackOs.linux : AppStackOs.windows; const stack = site.data.properties.functionAppConfig?.runtime?.name; - const stackValueForStacksAPI = (stack === RuntimeStacks.dotnetIsolated || stack === RuntimeStacks.dotnet) ? RuntimeStacks.dotnet : stack; + const stackValueForStacksAPI = + stack === RuntimeStacks.dotnetIsolated || stack === RuntimeStacks.dotnet ? RuntimeStacks.dotnet : stack; const stacksResponse = isFlexConsumption(site.data) && stackValueForStacksAPI ? await RuntimeStackService.getFunctionAppConfigurationStackForLocation(os, site.data.location, stackValueForStacksAPI) @@ -246,11 +247,19 @@ const AppSettingsDataLoader: React.FC = props => { } const sshEnabled = site.data.properties.sshEnabled; + const functionsRuntimeAdminIsolationEnabled: boolean = !!site.data.properties.functionsRuntimeAdminIsolationEnabled; setInitialValues({ ...convertStateToForm({ // @note(krmitta): Manually over-writing since the api returns null when sshEnabled property is not set in the database but the default is true - site: { ...site.data, properties: { ...site.data.properties, sshEnabled: isLinux && sshEnabled === null ? true : sshEnabled } }, + site: { + ...site.data, + properties: { + ...site.data.properties, + sshEnabled: isLinux && sshEnabled === null ? true : sshEnabled, + functionsRuntimeAdminIsolationEnabled: functionsRuntimeAdminIsolationEnabled, + }, + }, config: webConfig.data, metadata: metadata.metadata.success ? metadata.data : null, connectionStrings: connectionStrings.metadata.success ? connectionStrings.data : null, diff --git a/client-react/src/pages/app/app-settings/GeneralSettings/Platform.tsx b/client-react/src/pages/app/app-settings/GeneralSettings/Platform.tsx index 3092fb6f01..ad6649941f 100644 --- a/client-react/src/pages/app/app-settings/GeneralSettings/Platform.tsx +++ b/client-react/src/pages/app/app-settings/GeneralSettings/Platform.tsx @@ -483,6 +483,31 @@ const Platform: React.FC> = props => { infoBubbleMessage={t('portCountRange').format(VnetPrivatePortsCount.min, VnetPrivatePortsCount.max)} /> )} + {scenarioChecker.checkScenario(ScenarioIds.functionsAdminIsolationSupported, { site }).status !== 'disabled' && ( + + )} ); }; diff --git a/client-react/src/pages/app/app-settings/Sections/GeneralSettings.tsx b/client-react/src/pages/app/app-settings/Sections/GeneralSettings.tsx index 383de8879b..b047002ff0 100644 --- a/client-react/src/pages/app/app-settings/Sections/GeneralSettings.tsx +++ b/client-react/src/pages/app/app-settings/Sections/GeneralSettings.tsx @@ -75,7 +75,11 @@ const platformDirty = (values: AppSettingsFormValues, initialValues: AppSettings !isEqual(values.site.properties.clientAffinityEnabled, initialValues.site.properties.clientAffinityEnabled) || !isEqual(values.config.properties.webSocketsEnabled, initialValues.config.properties.webSocketsEnabled) || !isEqual(values.config.properties.minTlsCipherSuite, initialValues.config.properties.minTlsCipherSuite) || - !isEqual(!!values.site.properties.endToEndEncryptionEnabled, !!initialValues.site.properties.endToEndEncryptionEnabled) + !isEqual(!!values.site.properties.endToEndEncryptionEnabled, !!initialValues.site.properties.endToEndEncryptionEnabled) || + !isEqual( + !!values.site.properties.functionsRuntimeAdminIsolationEnabled, + !!initialValues.site.properties.functionsRuntimeAdminIsolationEnabled + ) ); }; diff --git a/client-react/src/utils/FwLinks.ts b/client-react/src/utils/FwLinks.ts index ab51e47e3a..ddd9790165 100644 --- a/client-react/src/utils/FwLinks.ts +++ b/client-react/src/utils/FwLinks.ts @@ -59,6 +59,7 @@ export const Links = { customErrorPagesLearnMore: 'https://go.microsoft.com/fwlink/?linkid=2245451', endToEndEncryptionLearnMore: 'https://go.microsoft.com/fwlink/?linkid=2252411', disableBasicAuthLearnMore: 'https://go.microsoft.com/fwlink/?linkid=2260316', + functionsRuntimeAdminIsolationEnabled: 'https://go.microsoft.com/fwlink/?linkid=2281478', }; export const DeploymentCenterLinks = { diff --git a/client-react/src/utils/scenario-checker/dynamic-linux.environment.ts b/client-react/src/utils/scenario-checker/dynamic-linux.environment.ts index 0d032cb263..7272057ffd 100644 --- a/client-react/src/utils/scenario-checker/dynamic-linux.environment.ts +++ b/client-react/src/utils/scenario-checker/dynamic-linux.environment.ts @@ -74,6 +74,13 @@ export class DynamicLinuxEnvironment extends Environment { return { status: 'disabled' }; }, }; + + this.scenarioChecks[ScenarioIds.functionsAdminIsolationSupported] = { + id: ScenarioIds.functionsAdminIsolationSupported, + runCheck: () => { + return { status: 'disabled' }; + }, + }; } public isCurrentEnvironment(input?: ScenarioCheckInput): boolean { diff --git a/client-react/src/utils/scenario-checker/flex-consumption-site.environment.ts b/client-react/src/utils/scenario-checker/flex-consumption-site.environment.ts index 659588f287..b4af675029 100644 --- a/client-react/src/utils/scenario-checker/flex-consumption-site.environment.ts +++ b/client-react/src/utils/scenario-checker/flex-consumption-site.environment.ts @@ -81,6 +81,13 @@ export class FlexConsumptionEnvironment extends Environment { return { status: 'disabled' }; }, }; + + this.scenarioChecks[ScenarioIds.functionsAdminIsolationSupported] = { + id: ScenarioIds.functionsAdminIsolationSupported, + runCheck: () => { + return { status: 'disabled' }; + }, + }; } public isCurrentEnvironment(input?: ScenarioCheckInput): boolean { diff --git a/client-react/src/utils/scenario-checker/scenario-ids.ts b/client-react/src/utils/scenario-checker/scenario-ids.ts index 05980a5b34..5c456f0d39 100644 --- a/client-react/src/utils/scenario-checker/scenario-ids.ts +++ b/client-react/src/utils/scenario-checker/scenario-ids.ts @@ -124,4 +124,5 @@ export class ScenarioIds { public static readonly enableE2ETlsEncryption = 'enableE2ETlsEncryption'; public static readonly ftpBasicAuthSupported = 'ftpBasicAuthSupported'; public static readonly ipModeSupported = 'ipModeSupported'; + public static readonly functionsAdminIsolationSupported = 'functionsAdminIsolationSupported'; } diff --git a/client/src/app/shared/models/portal-resources.ts b/client/src/app/shared/models/portal-resources.ts index 08e37db27c..ffc40ba060 100644 --- a/client/src/app/shared/models/portal-resources.ts +++ b/client/src/app/shared/models/portal-resources.ts @@ -1477,6 +1477,8 @@ export class PortalResources { public static diagnoseAndSolveProblems = 'diagnoseAndSolveProblems'; public static stackSettings = 'stackSettings'; public static platformSettings = 'platformSettings'; + public static functionsAdminIsolation = 'functionsAdminIsolation'; + public static functionsAdminIsolationInfoBubble = 'functionsAdminIsolationInfoBubble'; public static debugging = 'debugging'; public static modifiedTag = 'modifiedTag'; public static directToEnvironmentVariablesInfoMessage = 'directToEnvironmentVariablesInfoMessage'; diff --git a/server/Resources/Resources.resx b/server/Resources/Resources.resx index b239386677..fe7908c25b 100644 --- a/server/Resources/Resources.resx +++ b/server/Resources/Resources.resx @@ -4589,6 +4589,12 @@ Set to "External URL" to use an API definition that is hosted elsewhere. Platform settings + + Functions admin isolation + + + Enable this feature to require Function App administrative actions to go through Azure Resource Manager. + Debugging