Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

appservice - support disabling access for default basic auth #23900

Merged
merged 10 commits into from
Nov 16, 2023
Merged
71 changes: 50 additions & 21 deletions internal/services/appservice/linux_function_app_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,29 @@ type LinuxFunctionAppDataSourceModel struct {
StorageUsesMSI bool `tfschema:"storage_uses_managed_identity"` // Storage uses MSI not account key
StorageKeyVaultSecretID string `tfschema:"storage_key_vault_secret_id"`

AppSettings map[string]string `tfschema:"app_settings"`
AuthSettings []helpers.AuthSettings `tfschema:"auth_settings"`
AuthV2Settings []helpers.AuthV2Settings `tfschema:"auth_settings_v2"`
Availability string `tfschema:"availability"`
Backup []helpers.Backup `tfschema:"backup"` // Not supported on Dynamic or Basic plans
BuiltinLogging bool `tfschema:"builtin_logging_enabled"`
ClientCertEnabled bool `tfschema:"client_certificate_enabled"`
ClientCertMode string `tfschema:"client_certificate_mode"`
ClientCertExclusionPaths string `tfschema:"client_certificate_exclusion_paths"`
ConnectionStrings []helpers.ConnectionString `tfschema:"connection_string"`
DailyMemoryTimeQuota int `tfschema:"daily_memory_time_quota"`
Enabled bool `tfschema:"enabled"`
FunctionExtensionsVersion string `tfschema:"functions_extension_version"`
ForceDisableContentShare bool `tfschema:"content_share_force_disabled"`
HttpsOnly bool `tfschema:"https_only"`
PublicNetworkAccess bool `tfschema:"public_network_access_enabled"`
SiteConfig []helpers.SiteConfigLinuxFunctionApp `tfschema:"site_config"`
StickySettings []helpers.StickySettings `tfschema:"sticky_settings"`
Tags map[string]string `tfschema:"tags"`
VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"`

AppSettings map[string]string `tfschema:"app_settings"`
AuthSettings []helpers.AuthSettings `tfschema:"auth_settings"`
AuthV2Settings []helpers.AuthV2Settings `tfschema:"auth_settings_v2"`
Availability string `tfschema:"availability"`
Backup []helpers.Backup `tfschema:"backup"` // Not supported on Dynamic or Basic plans
BuiltinLogging bool `tfschema:"builtin_logging_enabled"`
ClientCertEnabled bool `tfschema:"client_certificate_enabled"`
ClientCertMode string `tfschema:"client_certificate_mode"`
ClientCertExclusionPaths string `tfschema:"client_certificate_exclusion_paths"`
ConnectionStrings []helpers.ConnectionString `tfschema:"connection_string"`
DailyMemoryTimeQuota int `tfschema:"daily_memory_time_quota"`
Enabled bool `tfschema:"enabled"`
FunctionExtensionsVersion string `tfschema:"functions_extension_version"`
ForceDisableContentShare bool `tfschema:"content_share_force_disabled"`
HttpsOnly bool `tfschema:"https_only"`
PublicNetworkAccess bool `tfschema:"public_network_access_enabled"`
PublishingDeployBasicAuthEnabled bool `tfschema:"webdeploy_publish_basic_authentication_enabled"`
PublishingFTPBasicAuthEnabled bool `tfschema:"ftp_publish_basic_authentication_enabled"`
SiteConfig []helpers.SiteConfigLinuxFunctionApp `tfschema:"site_config"`
StickySettings []helpers.StickySettings `tfschema:"sticky_settings"`
Tags map[string]string `tfschema:"tags"`

VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"`
CustomDomainVerificationId string `tfschema:"custom_domain_verification_id"`
DefaultHostname string `tfschema:"default_hostname"`
HostingEnvId string `tfschema:"hosting_environment_id"`
Expand Down Expand Up @@ -257,6 +259,16 @@ func (d LinuxFunctionAppDataSource) Attributes() map[string]*pluginsdk.Schema {

"site_credential": helpers.SiteCredentialSchema(),

"webdeploy_publish_basic_authentication_enabled": {
Type: pluginsdk.TypeBool,
Computed: true,
},

"ftp_publish_basic_authentication_enabled": {
Type: pluginsdk.TypeBool,
Computed: true,
},

"sticky_settings": helpers.StickySettingsComputedSchema(),

"virtual_network_subnet_id": {
Expand Down Expand Up @@ -362,6 +374,23 @@ func (d LinuxFunctionAppDataSource) Read() sdk.ResourceFunc {
PublicNetworkAccess: !strings.EqualFold(pointer.From(props.PublicNetworkAccess), helpers.PublicNetworkAccessDisabled),
}

basicAuthFTP := true
if basicAuthFTPResp, err := client.GetFtpAllowed(ctx, id.ResourceGroup, id.SiteName); err != nil {
return fmt.Errorf("retrieving state of FTP Basic Auth for %s: %+v", id, err)
} else if csmProps := basicAuthFTPResp.CsmPublishingCredentialsPoliciesEntityProperties; csmProps != nil {
basicAuthFTP = pointer.From(csmProps.Allow)
}

basicAuthWebDeploy := true
if basicAuthWebDeployResp, err := client.GetScmAllowed(ctx, id.ResourceGroup, id.SiteName); err != nil {
return fmt.Errorf("retrieving state of WebDeploy Basic Auth for %s: %+v", id, err)
} else if csmProps := basicAuthWebDeployResp.CsmPublishingCredentialsPoliciesEntityProperties; csmProps != nil {
basicAuthWebDeploy = pointer.From(csmProps.Allow)
}

state.PublishingFTPBasicAuthEnabled = basicAuthFTP
state.PublishingDeployBasicAuthEnabled = basicAuthWebDeploy

if hostingEnv := props.HostingEnvironmentProfile; hostingEnv != nil {
state.HostingEnvId = pointer.From(hostingEnv.ID)
}
Expand Down
120 changes: 98 additions & 22 deletions internal/services/appservice/linux_function_app_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,30 @@ type LinuxFunctionAppModel struct {
StorageUsesMSI bool `tfschema:"storage_uses_managed_identity"` // Storage uses MSI not account key
StorageKeyVaultSecretID string `tfschema:"storage_key_vault_secret_id"`

AppSettings map[string]string `tfschema:"app_settings"`
StickySettings []helpers.StickySettings `tfschema:"sticky_settings"`
AuthSettings []helpers.AuthSettings `tfschema:"auth_settings"`
AuthV2Settings []helpers.AuthV2Settings `tfschema:"auth_settings_v2"`
Backup []helpers.Backup `tfschema:"backup"` // Not supported on Dynamic or Basic plans
BuiltinLogging bool `tfschema:"builtin_logging_enabled"`
ClientCertEnabled bool `tfschema:"client_certificate_enabled"`
ClientCertMode string `tfschema:"client_certificate_mode"`
ClientCertExclusionPaths string `tfschema:"client_certificate_exclusion_paths"`
ConnectionStrings []helpers.ConnectionString `tfschema:"connection_string"`
DailyMemoryTimeQuota int `tfschema:"daily_memory_time_quota"` // TODO - Value ignored in for linux apps, even in Consumption plans?
Enabled bool `tfschema:"enabled"`
FunctionExtensionsVersion string `tfschema:"functions_extension_version"`
ForceDisableContentShare bool `tfschema:"content_share_force_disabled"`
HttpsOnly bool `tfschema:"https_only"`
KeyVaultReferenceIdentityID string `tfschema:"key_vault_reference_identity_id"`
PublicNetworkAccess bool `tfschema:"public_network_access_enabled"`
SiteConfig []helpers.SiteConfigLinuxFunctionApp `tfschema:"site_config"`
StorageAccounts []helpers.StorageAccount `tfschema:"storage_account"`
Tags map[string]string `tfschema:"tags"`
VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"`
ZipDeployFile string `tfschema:"zip_deploy_file"`
AppSettings map[string]string `tfschema:"app_settings"`
StickySettings []helpers.StickySettings `tfschema:"sticky_settings"`
AuthSettings []helpers.AuthSettings `tfschema:"auth_settings"`
AuthV2Settings []helpers.AuthV2Settings `tfschema:"auth_settings_v2"`
Backup []helpers.Backup `tfschema:"backup"` // Not supported on Dynamic or Basic plans
BuiltinLogging bool `tfschema:"builtin_logging_enabled"`
ClientCertEnabled bool `tfschema:"client_certificate_enabled"`
ClientCertMode string `tfschema:"client_certificate_mode"`
ClientCertExclusionPaths string `tfschema:"client_certificate_exclusion_paths"`
ConnectionStrings []helpers.ConnectionString `tfschema:"connection_string"`
DailyMemoryTimeQuota int `tfschema:"daily_memory_time_quota"` // TODO - Value ignored in for linux apps, even in Consumption plans?
Enabled bool `tfschema:"enabled"`
FunctionExtensionsVersion string `tfschema:"functions_extension_version"`
ForceDisableContentShare bool `tfschema:"content_share_force_disabled"`
HttpsOnly bool `tfschema:"https_only"`
KeyVaultReferenceIdentityID string `tfschema:"key_vault_reference_identity_id"`
PublicNetworkAccess bool `tfschema:"public_network_access_enabled"`
SiteConfig []helpers.SiteConfigLinuxFunctionApp `tfschema:"site_config"`
StorageAccounts []helpers.StorageAccount `tfschema:"storage_account"`
Tags map[string]string `tfschema:"tags"`
VirtualNetworkSubnetID string `tfschema:"virtual_network_subnet_id"`
ZipDeployFile string `tfschema:"zip_deploy_file"`
PublishingDeployBasicAuthEnabled bool `tfschema:"webdeploy_publish_basic_authentication_enabled"`
PublishingFTPBasicAuthEnabled bool `tfschema:"ftp_publish_basic_authentication_enabled"`

// Computed
CustomDomainVerificationId string `tfschema:"custom_domain_verification_id"`
Expand Down Expand Up @@ -262,6 +264,18 @@ func (r LinuxFunctionAppResource) Arguments() map[string]*pluginsdk.Schema {
Default: true,
},

"webdeploy_publish_basic_authentication_enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: true,
},

"ftp_publish_basic_authentication_enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: true,
},

"site_config": helpers.SiteConfigSchemaLinuxFunctionApp(),

"sticky_settings": helpers.StickySettingsSchema(),
Expand Down Expand Up @@ -531,6 +545,29 @@ func (r LinuxFunctionAppResource) Create() sdk.ResourceFunc {
return fmt.Errorf("waiting for creation of Linux %s: %+v", id, err)
}

// (@jackofallops) - updating the policy for publishing credentials resets the `Use32BitWorkerProcess` property
if !functionApp.PublishingDeployBasicAuthEnabled {
sitePolicy := web.CsmPublishingCredentialsPoliciesEntity{
CsmPublishingCredentialsPoliciesEntityProperties: &web.CsmPublishingCredentialsPoliciesEntityProperties{
Allow: pointer.To(false),
},
}
if _, err := client.UpdateScmAllowed(ctx, id.ResourceGroup, id.SiteName, sitePolicy); err != nil {
return fmt.Errorf("setting basic auth for deploy publishing credentials for %s: %+v", id, err)
}
}

if !functionApp.PublishingFTPBasicAuthEnabled {
sitePolicy := web.CsmPublishingCredentialsPoliciesEntity{
CsmPublishingCredentialsPoliciesEntityProperties: &web.CsmPublishingCredentialsPoliciesEntityProperties{
Allow: pointer.To(false),
},
}
if _, err := client.UpdateFtpAllowed(ctx, id.ResourceGroup, id.SiteName, sitePolicy); err != nil {
return fmt.Errorf("setting basic auth for ftp publishing credentials for %s: %+v", id, err)
}
}

updateFuture, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.SiteName, siteEnvelope)
if err != nil {
return fmt.Errorf("updating properties of Linux %s: %+v", id, err)
Expand Down Expand Up @@ -689,6 +726,20 @@ func (r LinuxFunctionAppResource) Read() sdk.ResourceFunc {
return fmt.Errorf("reading logs configuration for Linux %s: %+v", id, err)
}

basicAuthFTP := true
if basicAuthFTPResp, err := client.GetFtpAllowed(ctx, id.ResourceGroup, id.SiteName); err != nil {
return fmt.Errorf("retrieving state of FTP Basic Auth for %s: %+v", id, err)
} else if csmProps := basicAuthFTPResp.CsmPublishingCredentialsPoliciesEntityProperties; csmProps != nil {
basicAuthFTP = pointer.From(csmProps.Allow)
}

basicAuthWebDeploy := true
if basicAuthWebDeployResp, err := client.GetScmAllowed(ctx, id.ResourceGroup, id.SiteName); err != nil {
return fmt.Errorf("retrieving state of WebDeploy Basic Auth for %s: %+v", id, err)
} else if csmProps := basicAuthWebDeployResp.CsmPublishingCredentialsPoliciesEntityProperties; csmProps != nil {
basicAuthWebDeploy = pointer.From(csmProps.Allow)
}

state := LinuxFunctionAppModel{
Name: id.SiteName,
ResourceGroup: id.ResourceGroup,
Expand All @@ -707,6 +758,9 @@ func (r LinuxFunctionAppResource) Read() sdk.ResourceFunc {
PublicNetworkAccess: !strings.EqualFold(pointer.From(props.PublicNetworkAccess), helpers.PublicNetworkAccessDisabled),
}

state.PublishingFTPBasicAuthEnabled = basicAuthFTP
state.PublishingDeployBasicAuthEnabled = basicAuthWebDeploy

if hostingEnv := props.HostingEnvironmentProfile; hostingEnv != nil {
hostingEnvId, err := parse.AppServiceEnvironmentIDInsensitively(*hostingEnv.ID)
if err != nil {
Expand Down Expand Up @@ -1005,6 +1059,28 @@ func (r LinuxFunctionAppResource) Update() sdk.ResourceFunc {
return fmt.Errorf("waiting to update %s: %+v", id, err)
}

if metadata.ResourceData.HasChange("ftp_publish_basic_authentication_enabled") {
sitePolicy := web.CsmPublishingCredentialsPoliciesEntity{
CsmPublishingCredentialsPoliciesEntityProperties: &web.CsmPublishingCredentialsPoliciesEntityProperties{
Allow: pointer.To(state.PublishingFTPBasicAuthEnabled),
},
}
if _, err := client.UpdateFtpAllowed(ctx, id.ResourceGroup, id.SiteName, sitePolicy); err != nil {
return fmt.Errorf("setting basic auth for ftp publishing credentials for %s: %+v", id, err)
}
}

if metadata.ResourceData.HasChange("webdeploy_publish_basic_authentication_enabled") {
sitePolicy := web.CsmPublishingCredentialsPoliciesEntity{
CsmPublishingCredentialsPoliciesEntityProperties: &web.CsmPublishingCredentialsPoliciesEntityProperties{
Allow: pointer.To(state.PublishingDeployBasicAuthEnabled),
},
}
if _, err := client.UpdateScmAllowed(ctx, id.ResourceGroup, id.SiteName, sitePolicy); err != nil {
return fmt.Errorf("setting basic auth for deploy publishing credentials for %s: %+v", id, err)
}
}

if _, err := client.UpdateConfiguration(ctx, id.ResourceGroup, id.SiteName, web.SiteConfigResource{SiteConfig: existing.SiteConfig}); err != nil {
return fmt.Errorf("updating Site Config for Linux %s: %+v", id, err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2903,6 +2903,9 @@ resource "azurerm_linux_function_app" "test" {
}
}

ftp_publish_basic_authentication_enabled = false
webdeploy_publish_basic_authentication_enabled = false

tags = {
terraform = "true"
Env = "AccTest"
Expand Down Expand Up @@ -3095,6 +3098,9 @@ resource "azurerm_linux_function_app" "test" {
connection_string_names = ["First"]
}

ftp_publish_basic_authentication_enabled = false
webdeploy_publish_basic_authentication_enabled = false

tags = {
terraform = "true"
Env = "AccTest"
Expand Down
Loading
Loading