@@ -6785,6 +6785,13 @@ def upload_ssl_cert(cmd, resource_group_name,
67856785 # Check if this is a Flex Consumption function app
67866786 is_flex = is_flex_functionapp(cmd.cli_ctx, resource_group_name, name)
67876787
6788+ # Validate parameter usage
6789+ if is_flex and slot:
6790+ raise ArgumentUsageError("--slot is not supported for Flex Consumption function apps. "
6791+ "Site-scoped certificates apply to the parent app.")
6792+ if load_to_code is not None and not is_flex:
6793+ raise ArgumentUsageError("--load-to-code is only supported for Flex Consumption function apps.")
6794+
67886795 # For Flex Consumption apps, use the site-scoped certificates endpoint (slots not supported)
67896796 if is_flex:
67906797 # Build certificate envelope as dict to include loadCertificateToWebsitesSettings
@@ -6830,6 +6837,9 @@ def list_ssl_certs(cmd, resource_group_name, name=None):
68306837 # Check if this is a Flex Consumption function app
68316838 if name and is_flex_functionapp(cmd.cli_ctx, resource_group_name, name):
68326839 return client.site_certificates.list(resource_group_name=resource_group_name, name=name)
6840+ if name:
6841+ raise ArgumentUsageError("--name is only supported for Flex Consumption function apps. "
6842+ "For other app types, certificates are managed at the resource group level.")
68336843 return client.certificates.list_by_resource_group(resource_group_name)
68346844
68356845
@@ -6843,6 +6853,9 @@ def show_ssl_cert(cmd, resource_group_name, certificate_name, name=None):
68436853 name=name,
68446854 certificate_name=certificate_name
68456855 )
6856+ if name:
6857+ raise ArgumentUsageError("--name is only supported for Flex Consumption function apps. "
6858+ "For other app types, certificates are managed at the resource group level.")
68466859 return client.certificates.get(resource_group_name, certificate_name)
68476860
68486861
@@ -6861,6 +6874,9 @@ def delete_ssl_cert(cmd, resource_group_name, certificate_thumbprint, name=None)
68616874 )
68626875 raise ResourceNotFoundError("Certificate for thumbprint '{}' not found".format(certificate_thumbprint))
68636876
6877+ if name:
6878+ raise ArgumentUsageError("--name is only supported for Flex Consumption function apps. "
6879+ "For other app types, certificates are managed at the resource group level.")
68646880 webapp_certs = client.certificates.list_by_resource_group(resource_group_name)
68656881 for webapp_cert in webapp_certs:
68666882 if webapp_cert.thumbprint == certificate_thumbprint:
@@ -6931,33 +6947,55 @@ def import_ssl_cert(cmd, resource_group_name, key_vault, key_vault_certificate_n
69316947 if asc.name == key_vault_certificate_name:
69326948 kv_secret_name = asc.certificates[key_vault_certificate_name].key_vault_secret_name
69336949 break
6950+ else:
6951+ logger.warning("Unable to check App Service Certificate orders. "
6952+ "If '%s' is an App Service Certificate, the import may not resolve "
6953+ "the correct Key Vault secret name.", key_vault_certificate_name)
69346954
69356955 # if kv_secret_name is not populated, it is not an appservice certificate, proceed for KV certificates
69366956 if not kv_secret_name:
69376957 kv_secret_name = key_vault_certificate_name
69386958
69396959 cert_name = certificate_name or '{}-{}-{}'.format(resource_group_name, kv_name, key_vault_certificate_name)
69406960
6941- lnk = 'https://azure.github.io/AppService/2016/05/24/Deploying-Azure-Web-App-Certificate-through-Key-Vault.html'
6942- lnk_msg = 'Find more details here: {}'.format(lnk)
6943- if not _check_service_principal_permissions(cmd, kv_resource_group_name, kv_name, kv_subscription):
6944- logger.warning('Unable to verify Key Vault permissions.')
6945- logger.warning('You may need to grant Microsoft.Azure.WebSites service principal the Secret:Get permission')
6946- logger.warning(lnk_msg)
6961+ # When using MSI, the app's managed identity accesses Key Vault, not the service principal
6962+ if enable_using_msi:
6963+ logger.warning('Using managed identity to access Key Vault. '
6964+ 'Ensure the app\'s managed identity has the permission on the Key Vault.')
6965+ else:
6966+ lnk = 'https://azure.github.io/AppService/2016/05/24/Deploying-Azure-Web-App-Certificate-through-Key-Vault.html'
6967+ lnk_msg = 'Find more details here: {}'.format(lnk)
6968+ if not _check_service_principal_permissions(cmd, kv_resource_group_name, kv_name, kv_subscription):
6969+ logger.warning('Unable to verify Key Vault permissions.')
6970+ logger.warning('You may need to grant Microsoft.Azure.WebSites service principal the Secret:Get permission')
6971+ logger.warning(lnk_msg)
69476972
69486973 kv_cert_def = Certificate(location=location, key_vault_id=kv_id, password='',
69496974 key_vault_secret_name=kv_secret_name)
69506975
69516976 # Check if this is a Flex Consumption function app
6952- if name and is_flex_functionapp(cmd.cli_ctx, resource_group_name, name):
6977+ is_flex = name and is_flex_functionapp(cmd.cli_ctx, resource_group_name, name)
6978+
6979+ # Validate parameter usage
6980+ if load_to_code is not None and not is_flex:
6981+ raise ArgumentUsageError("--load-to-code is only supported for Flex Consumption function apps.")
6982+ if enable_using_msi is not None and not is_flex:
6983+ raise ArgumentUsageError("--enable-using-msi is only supported for Flex Consumption function apps.")
6984+ if enable_using_msi and (not webapp.identity or not webapp.identity.type):
6985+ raise ArgumentUsageError(
6986+ "--enable-using-msi requires a managed identity assigned to the function app. "
6987+ "Assign one with: az functionapp identity assign -g {} -n {}".format(resource_group_name, name))
6988+
6989+ if is_flex:
69536990 # Build certificate envelope as dict to include loadCertificateToWebsitesSettings
69546991 # (not in SDK model yet)
69556992 cert_envelope = {
69566993 "location": location,
69576994 "properties": {
69586995 "keyVaultId": kv_id,
69596996 "password": "",
6960- "keyVaultSecretName": kv_secret_name
6997+ "keyVaultSecretName": kv_secret_name,
6998+ "serverFarmId": get_site_server_farm_id(webapp)
69616999 }
69627000 }
69637001 if load_to_code is not None:
@@ -7007,6 +7045,11 @@ def create_managed_ssl_cert(cmd, resource_group_name, name, hostname, slot=None,
70077045 # Check if this is a Flex Consumption function app
70087046 is_flex = is_flex_functionapp(cmd.cli_ctx, resource_group_name, name)
70097047
7048+ # Validate parameter usage
7049+ if is_flex and slot:
7050+ raise ArgumentUsageError("--slot is not supported for Flex Consumption function apps. "
7051+ "Site-scoped certificates apply to the parent app.")
7052+
70107053 # Default certificate_name to hostname if not provided
70117054 if not certificate_name:
70127055 certificate_name = hostname
@@ -7091,6 +7134,11 @@ def _update_ssl_binding(cmd, resource_group_name, name, certificate_thumbprint,
70917134 # Check if this is a Flex Consumption function app
70927135 is_flex = is_flex_functionapp(cmd.cli_ctx, resource_group_name, name)
70937136
7137+ # Validate parameter usage for Flex apps
7138+ if is_flex and slot:
7139+ raise ArgumentUsageError("--slot is not supported for Flex Consumption function apps. "
7140+ "Site-scoped certificates apply to the parent app.")
7141+
70947142 found_cert = None
70957143
70967144 # For Flex Consumption apps, search in site-scoped certificates
@@ -7121,6 +7169,12 @@ def _update_ssl_binding(cmd, resource_group_name, name, certificate_thumbprint,
71217169
71227170 if found_cert:
71237171 if not hostname:
7172+ # For Flex Consumption apps, site-scoped certificates may not populate host_names
7173+ # Require --hostname to be specified explicitly in this case
7174+ if is_flex and (not found_cert.host_names or len(found_cert.host_names) == 0):
7175+ raise ArgumentUsageError(
7176+ "The site-scoped certificate does not have associated host names. "
7177+ "Please specify the hostname explicitly using --hostname.")
71247178 if len(found_cert.host_names) == 1 and not found_cert.host_names[0].startswith('*'):
71257179 return _update_host_name_ssl_state(cmd, resource_group_name, name, webapp,
71267180 found_cert.host_names[0], ssl_type,
0 commit comments