How to edit Azure App Service using Azure Python SDK? - azure

I'm following the example here https://learn.microsoft.com/en-us/azure/developer/python/azure-sdk-example-web-app?tabs=cmd#4-write-code-to-provision-and-deploy-a-web-app trying to update an existing App Service using the Python SDK.
Here is my code
from azure.mgmt.web import WebSiteManagementClient
from azure.common.client_factory import get_client_from_cli_profile
import os
def insert_access_restriction():
rg_name = os.environ.get('RESOURCE_GROUP_NAME', None)
location = os.environ.get('LOCATION', None)
sp_name = os.environ.get('SERVICE_PLAN_NAME', None)
web_app_name = os.environ.get('WEB_APP_NAME', None)
sub_id = os.environ.get('AZURE_SUBSCRIPTION_ID', None)
app_service_client = get_client_from_cli_profile(WebSiteManagementClient)
poller = app_service_client.app_service_plans.create_or_update(rg_name,
sp_name,
{
"location": location,
"reserved": True,
"sku" : {"name" : "S1"}
}
)
plan_result = poller.result()
poller = app_service_client.web_apps.create_or_update(rg_name,
web_app_name,
{
"location": location,
"server_farm_id": plan_result.id,
"site_config": {
"ip_restriction": {
"ip_address": "3.3.3.3/32"
},
"ip_restriction": {
"ip_address": "4.4.4.4/32"
}
}
}
)
The call to this function app_service_client.app_service_plans.create_or_update returns
azure.mgmt.web.v2019_08_01.models._models_py3.DefaultErrorResponseException:
Operation returned an invalid status code 'Bad Request'
My location is centralus. The goal of this program is to update the ip restrictions on an existing app service programmatically from a Function App when a new list of ip addresses is added to a storage container. The error is very vague, how do I get an existing app service plan, its app service, and then update the app service using the Python SDK?

if you want to update the ip restrictions settings on an existing app service with python sdk, please refer to the following code
Create a service principal and assign Contributor to the sp
az login
# create sp and assign Contributor role to the sp at subscription level
az ad sp create-for-rbac -n "MyApp"
Code
client_id = 'your sp appId'
secret = 'your sp password'
tenant = 'your sp tenant'
credentials = ServicePrincipalCredentials(
client_id = client_id,
secret = secret,
tenant = tenant
)
Subscription_Id = ''
web_client=WebSiteManagementClient(
credentials,
Subscription_Id
)
resorurce_group_name='your appservice group name'
name='you appservice name'
web_client.web_apps.create_or_update_configuration(resorurce_group_name, name,{
'ip_security_restrictions':[
{
'ip_address': "0.0.0.0/0",
'action': "Allow",
'priority': 30,
'name': "test"
}
]
})
for more details, please refer to here and here
#Update
If you want to run the script in Azure function, please refer to the following steps.
Create Azure function
Enable Azure MSI for Azure Function
Assign role fro the MSI
code (I use HTTP trigger to get web app configuration)
import logging
import pyodbc
import json
import azure.functions as func
from msrestazure.azure_active_directory import MSIAuthentication
from azure.mgmt.web import WebSiteManagementClient
async def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
creds =MSIAuthentication()
Subscription_Id = 'e5b0fcfa-e859-43f3-8d84-5e5fe29f4c68'
group_name='0730BowmanWindowAndLinux2'
name='413Bowman'
web_client=WebSiteManagementClient(
creds,
Subscription_Id
)
result =web_client.web_apps.get_configuration(group_name, name,raw=True)
return func.HttpResponse(json.dumps(result.response.json()))

Related

How to setup an emergency access accounts in Azure AD using Terraform?

I have configured the emergency access accounts in Azure AD following the article
https://learn.microsoft.com/en-us/azure/active-directory/roles/security-emergency-access however I want this to be configured using the Terraform script.
How to setup an emergency access accounts in Azure AD using Terraform?
First You need a create a App Registration, add the "Owner" role assignment for the App Registration. Use tenant_id, client_id, client_secret in the provider block.
Follow the link to create a App Registration: https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
Provide Required Api Permissions to the App Reg. Once you Create the App Registration and client secret(Store in a Key Vault Secret as it will be shown only one time). Open Subscription>Access control (IAM)>Add Role assignments>Owner> Select members(select your app registration)> Next>finish.
API Permissions Screenshot :
[App Registration API Permissions][1]
It's fine if you have already created a App Registration. App Registration must have owner role assignments and domain, directory role assignment read write permissions.
Use the below code you can able to create a User and Assign a role to the user.
terraform {
required_version = ">= 1.0.0"
required_providers {
azuread = {
source = "hashicorp/azuread"
version = "~> 2.0"
}
}
}
provider "azuread" {
#Configuration options
tenant_id = "tenant id of your"
client_id = "use client ID of your"
client_secret = "use client Secret of your"
}
resource "azuread_user" "aduser" {
user_principal_name = "azure.terraform#gmohankumar0341hotmail.onmicrosoft.com"
display_name = "azterraform"
mail_nickname = "aztf"
password = "Terraform#123"
country = "India"
}
resource "azuread_directory_role" "ad-role" {
display_name = "Global administrator"
depends_on = [
azuread_user.aduser
]
}
resource "azuread_directory_role_assignment" "aduser" {
role_id = azuread_directory_role.ad-role.template_id
principal_object_id = azuread_user.aduser.object_id
depends_on = [
azuread_user.aduser
]
}
[terraform apply command Screenshot][2]
[User created Reference Screenshot][3]
[Assigned roles Screenshot][4]
[1]: https://i.stack.imgur.com/KBr7y.png
[2]: https://i.stack.imgur.com/9zhP3.png
[3]: https://i.stack.imgur.com/6tlCe.png
[4]: https://i.stack.imgur.com/MScgE.png

Create Databricks token for another user

After deploying Databricks workspace I would like to add an application user and generate a token for it. Is there a way to have something like:
resource "databricks_service_principal" "app" {
application_id = "01234567-89ab-cdef-0123-456789abcdef"
}
resource "databricks_token" "token" {
service_principal_id = databricks_service_principal.app.application_id
comment = "A token"
}
Currently databricks_token doesn't support service_principal_id field, it only creates token for current user.
It depends on the cloud:
On AWS there is support for so-called "on behalf of" (OBO) token - there is a dedicated resource for it: databricks_obo_token (doc).
On Azure, you can create a separate provider instance to authenticate to Databricks using Service Principal authentication (doc) and generate token using that provider instance (although, frankly speaking, it's better always use AAD auth for service principals on Azure). Something like this:
# this will use "normal" provider instance
resource "databricks_service_principal" "app" {
application_id = "01234567-89ab-cdef-0123-456789abcdef"
}
# Provider instance for Service Principal
provider "databricks" {
host = azurerm_databricks_workspace.this.workspace_url
azure_workspace_resource_id = azurerm_databricks_workspace.this.id
azure_client_id = var.client_id
azure_client_secret = var.client_secret
azure_tenant_id = var.tenant_id
alias = "spn"
}
resource "databricks_token" "token" {
provider = databricks.spn
comment = "A token"
depends_on = [databricks_service_principal.app]
}

Bootstraping an Azure service account in Terraform

I am trying to write the Terraform to create an Azure "service account" and am getting quite confused by the distinction between what Azure AD calls "Applications" and "Service Principals". Effectively, I'm trying to mimic the following Azure CLI call:
az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/${subscription_id}"
The idea would be for a human administrator to run the Terraform, to set it up once, then those credentials could later be used to authenticate for the remaining IaC. (i.e., It's a bootstrapping exercise.)
I wish to do it in Terraform, rather than a Bash script, as it seems more explicit and fits with the rest of my IaC. This is what I have so far:
data "azurerm_subscription" "current" {}
data "azuread_client_config" "current" {}
resource "azuread_application" "terraform" {
display_name = "Terraform"
owners = [data.azuread_client_config.current.object_id]
}
resource "azuread_application_password" "terraform" {
application_object_id = azuread_application.terraform.object_id
}
# resource "azuread_service_principal" "terraform" {
# application_id = azuread_application.terraform.application_id
# owners = [data.azuread_client_config.current.object_id]
# }
#
# resource "azuread_service_principal_password" "terraform" {
# service_principal_id = azuread_service_principal.terraform.object_id
# }
resource "local_file" "azurerc" {
filename = ".azurerc"
file_permission = "0600"
content = <<EOF
export ARM_ENVIRONMENT="public"
export ARM_SUBSCRIPTION_ID="${data.azurerm_subscription.current.subscription_id}"
export ARM_TENANT_ID="${data.azuread_client_config.current.tenant_id}"
export ARM_CLIENT_ID="${azuread_application.terraform.application_id}"
export ARM_CLIENT_SECRET="${azuread_application_password.terraform.value}"
EOF
}
This runs, but later authenticating with the generated credentials gives an authentication error. Specifically, Terraforms says:
If you are accessing as application please make sure service principal is properly created in the tenant.
Clearly I haven't done that -- it's commented out in the above snippet -- but that's because this is where my understanding starts to break down. Why do I need both? Why do both the application and the service principal have password resources? If I generate passwords for both, which is the ARM_CLIENT_SECRET (I think the application password is the right one)? Then there's the role assignment: I see there's an azuread_app_role_assignment resource, but I'm having trouble unpicking it.
I am trying to write the Terraform to create an Azure "service
account" and am getting quite confused by the distinction between what
Azure AD calls "Applications" and "Service Principals".
Applications can be seen from Azure AD App registrations blade Where as Service Principals are other wise know as Enterprise Applications. The difference is well documented in this Microsoft Documentation.
This runs, but later authenticating with the generated credentials
gives an authentication error. Specifically, Terraforms says:
If you are accessing as application please make sure service principal
is properly created in the tenant.
This is because you have no associated service principal to that azure ad application which you have created from Terraform. The association is needed to access the application or authenticating to the azure environment with contributor role. When a App registration is created from portal it by default creates an association of AD app and Service principal , which by default results in creating a service principal for that app registration. It also applies the same concept when we use az ad sp create-for-rbac.
Effectively, I'm trying to mimic the following Azure CLI call:
az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/${subscription_id}"
You can use the below to mimic the above command :
provider "azurerm" {
features{}
}
provider "azuread" {}
data "azurerm_subscription" "current" {}
data "azuread_client_config" "current" {}
resource "azuread_application" "terraform" {
display_name = "Ansumantest"
owners = [data.azuread_client_config.current.object_id]
}
resource "azuread_application_password" "terraform" {
application_object_id = azuread_application.terraform.object_id
}
resource "azuread_service_principal" "terraform" {
application_id = azuread_application.terraform.application_id
owners = [data.azuread_client_config.current.object_id]
}
resource "azurerm_role_assignment" "example" {
scope = data.azurerm_subscription.current.id
role_definition_name = "Contributor"
principal_id = azuread_service_principal.terraform.object_id
}
resource "local_file" "azurerc" {
filename = ".azurerc"
file_permission = "0600"
content = <<EOF
export ARM_ENVIRONMENT="public"
export ARM_SUBSCRIPTION_ID="${data.azurerm_subscription.current.subscription_id}"
export ARM_TENANT_ID="${data.azuread_client_config.current.tenant_id}"
export ARM_CLIENT_ID="${azuread_application.terraform.application_id}"
export ARM_CLIENT_SECRET="${azuread_application_password.terraform.value}"
EOF
}
Output :
Using the above details I created a reosurce group in the subscription :
provider "azurerm" {
features{}
subscription_id = "88073b30-cadd-459e-b90b-8442c93573ae"
tenant_id = "ab078f81-xxxx-xxxx-xxxx-620b694ded30"
client_id = "c022ec46-xxxx-xxxx-xxxx-c72a9b82f429"
client_secret = "wdV7Q~8Grxxxxxxxxxxxxxx~SCwbRrKIq9"
}
resource "azurerm_resource_group" "name" {
name = "testansterraform"
location = "west us 2"
}

Azure PowerShell cmdlet Set-AzRouteConfig

I am trying to find out how Azure PowerShell cmdlet Set-AzRouteConfig works under the hood , what calls it makes to Azure APIs etc. The goal is to achieve a similar functionality using Azure SDK for Python.
For the set-AzRouteConfig operations to be performed in Azure SDK for python , It needs az-mgmt-network package so that it can use NetworkManagementClient Class to perform 2 operations i.e. RouteTableOperations and RouteOperations . For the updating the route present in a route_table you can use begin_create_or_update.
Example:
Code:
from azure.identity import AzureCliCredential
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.network.models import Route
credential = AzureCliCredential()
subscription_id = "b83c1ed3-xxxx-xxxx-xxxx-2b83a074c23f"
network_client = NetworkManagementClient(credential, subscription_id)
resource_group = "ansumantest"
location = "West US 2"
route_table_name = "ansuman-routetable"
route_name = "route1"
get_table=network_client.route_tables.get(resource_group,route_table_name)
print(get_table)
route_parameters= Route(name='route1',address_prefix='10.0.0.0/32',next_hop_type='VnetLocal')
set_route_config= network_client.routes.begin_create_or_update(resource_group,route_table_name,route_name,route_parameters)
get_route_config= network_client.routes.get(resource_group,route_table_name,route_name)
print(get_route_config)
Output:
Before Updating the route :
After updating the route :
Properties changed are address_prefix and next_hop_type.

Unauthorized error using Terraform to deploy app service on Azure

I am trying to deploy a windows container on azure app service with Terraform. The app service plan deploys fine, but I get an authorization error when the app service tries to deploy. I am using connection strings for an ACR instance with the admin user and password. Does anyone have some ideas?
The deployment works if I do it manually from the portal.
# Create an App Service Plan with Windows
resource "azurerm_app_service_plan" "appserviceplan" {
name = "${var.rg-name}-plan"
location = "westus"
resource_group_name = var.rg-name
# Define Windows as Host OS
kind = "xenon"
is_xenon = true
# Choose size
sku {
tier = "PremiumContainer"
size = "PC2"
}
}
# Create an Azure Web App for Containers in that App Service Plan
resource "azurerm_app_service" "dockerapp" {
name = "${var.rg-name}-dockerapp"
location = "westus"
resource_group_name = "${var.rg-name}"
app_service_plan_id = "${azurerm_app_service_plan.appserviceplan.id}"
# Configure Docker Image to load on start
site_config {
windows_fx_version = "DOCKER|apps.azurecr.io/test/container:latest"
}
app_settings = {
# Settings for private Container Registires
DOCKER_REGISTRY_SERVER_URL = "repo.azureco.io",
DOCKER_REGISTRY_SERVER_USERNAME = "admin user",
DOCKER_REGISTRY_SERVER_PASSWORD = "password"
}
}
Error:
Error: Error creating App Service "dockerapp" (Resource Group "resource-group"): web.AppsClient#CreateOrUpdate: Failure sending request: StatusCode=401 -- Original Error: Code="Unauthorized" Message="Access is denied. Not authorized. latest" Details=[{"Message":"Access is denied. Not authorized. latest"},{"Code":"Unauthorized"},{"ErrorEntity":{"Code":"Unauthorized","ExtendedCode":"01001","Message":"Access is denied. Not authorized. latest","MessageTemplate":"Access is denied.","Parameters":[]}}]
You could verify if the value of DOCKER_REGISTRY_SERVER_URL is correct, it should be a valid URL.
For example, It will look like this in your code.
app_settings = {
# Settings for private Container Registires
DOCKER_REGISTRY_SERVER_URL = "https://apps.azurecr.io",
DOCKER_REGISTRY_SERVER_USERNAME = "admin user",
DOCKER_REGISTRY_SERVER_PASSWORD = "password"
}
For more references, Here is an example of deploying a windows container on azure app service with Terraform.
Can you quickly check if the URL in DOCKER_REGISTRY_SERVER_URL is the same as you are using in site_config.windows_fx_version

Resources