just what i find

Archives 2024

How to: use custom / self-signed certificates with Requests in Python

In a previous post, I explained how to configure Azurite to use a self-signed certificate to enable OAuth authentication. One challenge with this method is that the Azure Python SDK will refuse to connect to azurite, reporting errors such as:

azure.core.exceptions.ServiceRequestError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)

This is because the the Azure SDK uses the Requests library, which in turn uses Certifi as its source of root certificates. Certifi provides a regularly updated bundle of the Mozilla root trust store, and our self-signed custom certificate obviously isn’t in Mozilla’s trust list!

How to: use Azurite with self-generated certificates for HTTPS in a Codespace or Devcontainer

I’ve been using Azurite to simulate Azure storage for my development. If you’re not familiar with it, Azurite is a local storage emulator for Azure Storage, and you can read my other post about how i’ve set up my devcontainer configuration to run Azurite as a service container. As my deployed code is using an Azure Managed Identity, I wanted ensure my development environment was consistent with this and also uses Azure DefaultAzureCredential credential provider class. In this post, i will talk through the steps required to switch from using a connection string (with a well-known account and key) to using OAuth and HTTPS, helping to increase feature parity between development and production, reducing the chances of mistakes.

How to: Use Azurite as a service container in Codespaces or Devcontainers

When developing with Azure Storage, it can significantly speed up your development process if you can use a local development environment, rather than constantly connecting directly to storage in Azure itself. This is where Azurite comes in - Azurite is a local storage emulator for Azure Storage, mimicing blob/container, queue and table storage. While there are lots of ways to get it running (e.g. from binary, manually using Docker etc.), I wanted to set it up as a service container in my devcontainer configuration which provides a few benefits:

How to: Create SAS with multiple permissions in Pulumi

In Pulumi, when calling pulumi_azure_native.storage.list_storage_account_service_sas_output() to generate a SAS, you pass the required permissions to the permissions: Input[str | Permissions | None] parameter. pulumi_azure_native.storage.Permissions is an enum, offering simple selections (R, L etc.):

# Create a shared access signature scoped to the container
app_container_signature = (
  pulumi.Output.all(resource_group.name, storage_account.name, app_container.name)
  .apply(
    lambda args: azure_native.storage.list_storage_account_service_sas_output(
      resource_group_name=args[0],
      account_name=args[1],
      protocols=azure_native.storage.HttpProtocol.HTTPS,
      shared_access_start_time="2022-01-01",
      shared_access_expiry_time="2030-01-01",
      resource=azure_native.storage.SignedResource.C,
      permissions=azure_native.storage.Permissions.R,
      content_type="application/json",
      cache_control="max-age=5",
      content_disposition="inline",
      content_encoding="deflate",
      canonicalized_resource=f"/blob/{args[1]}/{args[2]}",
    )
  )
  .apply(lambda result: pulumi.Output.secret(result.service_sas_token))
)

But you can also pass a string of permissions, any of R, L, D, W, C, A, or P, depending on the actions you want to allow for the SAS. This allows you to specify permissions for reading (R), listing (L), deleting (D), writing (W), creating (C), adding (A), or processing (P) blobs within the container, such as permissions="RWL":

How to: retrieve storage account primary key using Pulumi

Another note for myself. I wanted to use this to give my app access to the entire account. I thought they would be a property of pulumi_azure_native.storage.StorageAccount but they’re not. Instead you need to call pulumi_azure_native.storage.list_storage_account_keys().

import pulumi
import pulumi_azure_native as azure_native
config = pulumi.Config()
# Create a Resource Group
resource_group_name = config.require("resourceGroupName")
location = config.require("location")
resource_group = azure_native.resources.ResourceGroup(
  resource_group_name, resource_group_name=resource_group_name, location=location
)
# Create a Storage Account
storage_account = azure_native.storage.StorageAccount(
  config.require("storageAccountName"),
  resource_group_name=resource_group.name,
  sku=azure_native.storage.SkuArgs(
    name=azure_native.storage.SkuName.STANDARD_LRS,
  ),
  kind=azure_native.storage.Kind.STORAGE_V2,
  location=resource_group.location,
)
# fetch primary key
storage_account_primary_key = (
  pulumi.Output.all(resource_group.name, storage_account.name)
  .apply(lambda args: azure_native.storage.list_storage_account_keys(resource_group_name=args[0], account_name=args[1]))
  .apply(lambda accountKeys: pulumi.Output.secret(accountKeys.keys[0].value))
)

How to: check if a container exists without account level List permission

In a storage account, you can create a SAS scoped to a specific container, however, that SAS does not have permission to execute BlobClient.exists() as this requires at least list privileges on the parent object (e.g. the account), and when you try to perform the check, you’ll get this error:

azure.core.exceptions.HttpResponseError: This request is not authorized to perform this operation.

Note that this is an HttpResponseError, not a ClientAuthenticationError (which is actually a more specific error which extends HttpResponseError), so you need to interrogate the specific response code, although note that if the container client does not exist, you might also get a ClientAuthenticationError with this message:

Fix: "0 functions loaded" deploying Azure Functions from package

This post is mainly a reminder to myself, because i’ve made the same mistake a few times in different projects.

How and why to deploy Azure functions from a package

When using Azure Functions, you can simplify deployment and maintenance of your function by deploying from a package file rather than directly in to the function. This also has the benefit of reducing cold start times, particularly where there are a large number of dependencies.

Fix: Pulumi error Cannot modify this site because another operation is in progress creating Azure Function on Dynamic Consumption plan

Another post which is more to remind me than anything else. When creating an Azure Function in Pulumi, you may get the following error:

Cannot modify this site because another operation is in progress

After a bit of digging, i found this issue on the Pulumi repo, which points to a page on the Azure Functions wiki where they say:

If you run in a dedicated mode, you need to turn on the Always On setting for your Function App to run properly … When running in a Consumption Plan or Premium Plan you should not enable Always On.

Fix: Wordpress error "The response is not a valid JSON response when" uploading images

When uploading images to Wordpress, you may get this error. There are plenty of blogs online offering solutions, but they only apply to self-hosted instances - mine is hosted on just-what-i-find.onyx-sites.io/.

The error is a little pop up with the text The response is not a valid JSON response at the bottom of the screen when you try and upload an image:

Looking in the developer tools console on the browser shows one of two error messages: