iTranslated by AI
The Complete Guide to Setting Up Python and Azure SDK on Windows ARM64 (Copilot+ PC)
Introduction
Windows machines equipped with ARM64 processors (Snapdragon X Elite / Plus), such as the Surface Pro X, Copilot+ PC, and Surface Pro 11, are spreading rapidly. They are attractive as development machines because they have long battery life and are fanless and quiet, but when you try to do Azure development with Python, you will immediately run into a wall.
Why is being able to use the Azure SDK great?
By using the Azure SDK (azure-identity, azure-storage-blob, azure-cosmos, etc.), you can operate Azure resources from Python safely and easily.
# With the Azure SDK, you can upload files to Blob Storage in just a few lines
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
credential = DefaultAzureCredential() # Authentication is automatic!
client = BlobServiceClient(
account_url="https://myaccount.blob.core.windows.net",
credential=credential
)
blob_client = client.get_blob_client("my-container", "report.pdf")
with open("report.pdf", "rb") as f:
blob_client.upload_blob(f, overwrite=True)
Particularly important is DefaultAzureCredential. This class automatically determines the execution environment and switches between using az login authentication locally and Managed Identity on Azure. In other words, you can write an app that runs on both local and cloud environments without changing a single line of code.
Without the Azure SDK, you would need tedious code like calling the REST API directly and manually calculating the HMAC-SHA256 signature of the access key.
Why does the cryptography package become an issue?
cryptography is a cryptographic library for Python. It handles the core of security, such as SSL/TLS communication, certificate verification, and digital signatures. Even if you don't use it directly, azure-identity in the Azure SDK depends on it internally, so if this cannot be installed, the Azure SDK itself will not work.
The problem is that this package is written in three languages—Python + C + Rust—and requires native binaries during pip install. Usually, pre-built binaries (wheels) are published on PyPI, but wheels for Windows ARM64 simply do not exist. Therefore, it is necessary to build it from the source code.
Errors encountered
ERROR: Failed building wheel for cryptography
ImportError: DLL load failed while importing _rust: The specified procedure could not be found.
Workaround: WSL2 is also an option
As a quick workaround, there is WSL2 (Windows Subsystem for Linux). Since Linux ARM64 wheels are available on Ubuntu in WSL2, pip install azure-identity works in a single shot.
However, native Windows development is necessary in the following cases:
- You want to combine it with PowerShell scripts.
- You want to fully utilize native VS Code Python extensions.
- Projects using Windows-specific APIs (COM, Win32).
- You want to execute and debug directly locally without using Docker.
In this article, I will carefully explain the procedure for setting up the Azure SDK in a Windows ARM64 native environment without relying on WSL2, including background knowledge.
What you can solve in this article
| Issue | Solution |
|---|---|
pip install azure-identity fails |
Build cryptography from source |
Cannot import due to DLL load failed
|
Control DLL loading order with sitecustomize.py
|
| Cannot access Azure resources from local | Configure DefaultAzureCredential + RBAC |
Background: Why is this procedure necessary?
Wheel availability
Pre-built wheels for major platforms are published on PyPI for cryptography, but not all are supported:
| OS | Architecture | Wheel Availability |
|---|---|---|
| Windows | x64 | ✅ Available |
| Windows | ARM64 | ❌ None |
| macOS | ARM64 (Apple Silicon) | ✅ Available |
| Linux | x64 | ✅ Available |
| Linux | ARM64 | ✅ Available |
Windows ARM64 is the only one left behind. Therefore, you need to build it from source code yourself.
What is needed for source build
Because cryptography is written in three languages, the build requires three toolchains:
cryptography source code
├── Python part → Handled by pip (no additional tools needed)
├── C part → MSVC (Microsoft Visual C++) required
└── Rust part → Rust compiler (rustc) required
└── Link to OpenSSL → OpenSSL development libraries required
Furthermore, to create a .pyd (Python extension module) for ARM64, each tool must be able to output with ARM64 as the target.
Terminology
Before getting into the setup steps, let's summarize the terms that will appear.
Rust
A systems programming language developed by Mozilla. It balances memory safety and high performance. Since version 35, the cryptography package has implemented some of its cryptographic processes in Rust. Therefore, the Rust compiler (rustc) is required for the source build.
MSVC (Microsoft Visual C++)
A set of Microsoft's C/C++ compiler and linker. It is included in the Visual Studio Build Tools. Since cryptography also has parts written in C, the MSVC linker (link.exe) is required.
The important thing is that to create an ARM64 executable, you need the linker and libraries for ARM64. By default, only the ones for x64 are installed, so you must explicitly add the ARM64 components.
OpenSSL
The de facto standard library for encrypted communications. It is used for TLS/SSL connections, certificate verification, and more. The cryptography package links to OpenSSL to perform cryptographic operations, so OpenSSL header files (.h) and libraries (.lib) are required at build time.
DefaultAzureCredential
The authentication class for the Azure SDK introduced in the "Introduction". It automatically selects the optimal authentication method based on the execution environment:
| Execution Environment | Authentication Method Used |
|---|---|
| Azure App Service | Managed Identity |
Local (after az login) |
Azure CLI credentials |
| GitHub Actions | Federated identity tokens |
The goal of this article is to get this DefaultAzureCredential working in a local environment.
RBAC (Role-Based Access Control)
A mechanism for controlling "who" can do "what" to Azure resources using roles. For example, assigning the Storage Blob Data Contributor role allows reading, writing, and deleting blobs. To access Azure resources from a local environment using DefaultAzureCredential, you need to assign the appropriate roles to the az login user.
sitecustomize.py
A file that Python automatically loads upon startup. When placed in the site-packages/ directory, it is automatically executed first whenever any Python script is run. In this article, we use it to control the loading order of OpenSSL DLLs.
Prerequisites
- Windows 11 ARM64 (Surface Pro X / Copilot+ PC / Dev Kit, etc.)
- Python 3.12+ (Native ARM64 version)
- winget command available
-
Azure CLI installed and logged in with
az login(when accessing Azure resources)
Verification command:
# Check if Python is the ARM64 version
python -c "import platform; print(platform.machine())"
# → OK if "ARM64" is displayed (if "x86_64", it's the x64 emulation version)
Setup Procedure
Step 1. Installing the Rust Compiler
It is necessary for compiling the Rust code included in the cryptography source code.
winget install Rustlang.Rustup
rustup default stable
rustc --version
# → OK if rustc 1.xx.x (aarch64-pc-windows-msvc) is displayed
If aarch64-pc-windows-msvc is displayed, the Rust compiler for ARM64 is correctly installed.
Step 2. Installing Visual Studio Build Tools 2022
This is the MSVC toolchain required for compiling and linking C/C++ code.
winget install Microsoft.VisualStudio.2022.BuildTools `
--override "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --passive"
Adding ARM64 Components (⚠️ Administrator privileges required):
By default, only the linker and libraries for x64 are installed. To build for ARM64, you must explicitly add the ARM64 components.
$installer = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vs_installer.exe"
Start-Process -Verb RunAs -FilePath $installer -ArgumentList @(
"modify",
"--installPath", "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\BuildTools",
"--add", "Microsoft.VisualStudio.Component.VC.Tools.ARM64",
"--passive"
) -Wait
Verification (OK if True is returned):
Test-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\*\lib\arm64"
Step 3. Installing OpenSSL ARM64 Development Libraries
This is the cryptographic library that cryptography links to. Since both header files (.h) and static libraries (.lib) are required, install the Dev version.
winget install ShiningLight.OpenSSL.Dev
# → Installed to C:\Program Files\OpenSSL-Win64-ARM
Step 4. Creating a Virtual Environment
Create an isolated Python environment for each project.
python -m venv .venv
.\.venv\Scripts\Activate.ps1
Step 5. Building cryptography from Source
This is the most complex part of the procedure. To tell the build system where MSVC and OpenSSL are located, you need to set several environment variables before running pip install.
# --- Resolve MSVC location ---
$msvcVer = (Get-ChildItem "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC" |
Sort-Object Name -Descending | Select-Object -First 1).Name
$msvcBase = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\$msvcVer"
# --- Resolve Windows SDK location ---
$sdkVer = (Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\Include" |
Where-Object { $_.Name -match '^\d+\.' } |
Sort-Object Name -Descending | Select-Object -First 1).Name
# --- Set environment variables ---
# PATH: Use ARM64 native link.exe (Hostarm64\arm64)
$env:PATH = "$msvcBase\bin\Hostarm64\arm64;$env:PATH"
# INCLUDE: Where the compiler looks for header files
$env:INCLUDE = "$msvcBase\include;" + `
"${env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\ucrt;" + `
"${env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\shared;" + `
"${env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\um"
# LIB: Where the linker looks for libraries (specify the arm64 subfolder)
$env:LIB = "$msvcBase\lib\arm64;" + `
"${env:ProgramFiles(x86)}\Windows Kits\10\Lib\$sdkVer\ucrt\arm64;" + `
"${env:ProgramFiles(x86)}\Windows Kits\10\Lib\$sdkVer\um\arm64"
# --- Specify OpenSSL location ---
$env:OPENSSL_DIR = "C:\Program Files\OpenSSL-Win64-ARM"
# ⚠️ Libraries are in lib\VC\arm64\MD\, not directly under lib\
$env:OPENSSL_LIB_DIR = "C:\Program Files\OpenSSL-Win64-ARM\lib\VC\arm64\MD"
$env:OPENSSL_INCLUDE_DIR = "C:\Program Files\OpenSSL-Win64-ARM\include"
# --- Build & Install ---
pip install cryptography --no-binary cryptography
Meaning of each environment variable
| Environment Variable | Setting | Why is it necessary? |
|---|---|---|
PATH |
Directory containing MSVC's ARM64 link.exe | ARM64 binaries cannot be created if x64 link.exe is used |
INCLUDE |
MSVC headers + Windows SDK headers (ucrt, shared, um) | For the C compiler to resolve #include
|
LIB |
MSVC lib + Windows SDK lib (arm64 subfolder) | For the linker to find .lib files |
OPENSSL_DIR |
OpenSSL root directory | Referenced by the cryptography build script |
OPENSSL_LIB_DIR |
Location of OpenSSL .lib files |
Explicitly specified as they aren't directly under lib\
|
OPENSSL_INCLUDE_DIR |
Location of OpenSSL header files | To resolve #include <openssl/ssl.h>
|
Step 6. Avoiding Runtime DLL Conflicts
Even if the build is successful, you might encounter this error during import (though it may not occur in all environments):
ImportError: DLL load failed while importing _rust: The specified procedure could not be found.
Cause: The Rust extension of the built cryptography (_rust.pyd) requires OpenSSL DLLs at runtime. However, OpenSSL DLLs might also exist in C:\Windows\System32, and Python may load those first. Since they differ in version or export symbols from the OpenSSL used during the build, the loading fails.
Search order:
1. C:\Windows\System32\libcrypto-3.dll ← ❌ Wrong version
2. C:\Program Files\OpenSSL-Win64-ARM\bin\libcrypto-3-arm64.dll ← ✅ Correct version
Solution: Create sitecustomize.py within the venv to load the correct DLL first upon Python startup. Even if you don't see this error, it is recommended to set this up as a preventive measure.
# .venv/Lib/site-packages/sitecustomize.py
"""
OpenSSL DLL Preloading for Windows ARM64
To avoid conflicts with OpenSSL DLLs in System32,
load the OpenSSL DLLs used during the build first.
"""
import os
import sys
if sys.platform == "win32":
_openssl_bin = r"C:\Program Files\OpenSSL-Win64-ARM\bin"
if os.path.isdir(_openssl_bin):
os.add_dll_directory(_openssl_bin)
import ctypes
try:
ctypes.WinDLL(os.path.join(_openssl_bin, "libcrypto-3-arm64.dll"))
ctypes.WinDLL(os.path.join(_openssl_bin, "libssl-3-arm64.dll"))
except OSError:
pass # OpenSSL not installed — fall through
Step 7. Installing the Azure SDK
Now that cryptography is working, you can install the Azure SDK as usual.
If you want to install all the packages used in your project at once, it is a best practice to organize them in a requirements.txt file:
# requirements.txt
azure-identity # Authentication (DefaultAzureCredential) — almost essential
azure-storage-blob # Blob Storage
azure-cosmos # Cosmos DB
azure-ai-documentintelligence # Document Intelligence (AI)
openai # Azure OpenAI
azure-mgmt-resource # Azure Resource Manager (Resource Management)
azure-monitor-opentelemetry # Application Insights (Monitoring)
pip install -r requirements.txt
If you are just getting started with the basics, you only need the authentication package plus the service you want to use:
# Example: When using Blob Storage
pip install azure-identity azure-storage-blob
Step 8. Verification
python -c "from azure.identity import DefaultAzureCredential; print('azure-identity OK')"
python -c "from azure.storage.blob import BlobServiceClient; print('azure-storage-blob OK')"
If both display OK, the setup is complete! 🎉
(Optional) Accessing Azure Resources from Local
To use DefaultAzureCredential locally, you need to grant the az login user access rights to the Azure resources.
For Blob Storage
# Get your own object ID
$objectId = (az ad signed-in-user show --query id -o tsv)
# Grant read/write permissions to Blob Storage
az role assignment create `
--assignee-object-id $objectId `
--assignee-principal-type User `
--role "Storage Blob Data Contributor" `
--scope "/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RG>/providers/Microsoft.Storage/storageAccounts/<ACCOUNT>"
For Cosmos DB
az cosmosdb sql role assignment create `
--account-name <ACCOUNT> `
--resource-group <RG> `
--role-definition-name "Cosmos DB Built-in Data Contributor" `
--principal-id $objectId `
--scope "/"
Verification (Blob Example)
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
credential = DefaultAzureCredential()
client = BlobServiceClient(
account_url="https://<ACCOUNT>.blob.core.windows.net",
credential=credential
)
# List containers
for container in client.list_containers():
print(container["name"])
Troubleshooting
| Error | Cause | Action |
|---|---|---|
link.exe not found |
MSVC PATH is not set | Check the $env:PATH setting in Step 5 |
LNK4272: library machine type 'x64' conflicts with target 'ARM64' |
ARM64 MSVC components not installed | Perform the ARM64 addition in Step 2 |
Could not find OpenSSL |
OpenSSL environment variables not set | Check the 3 OPENSSL_* variables in Step 5 |
OpenSSL library not found at lib |
OPENSSL_LIB_DIR is incorrect |
Specify lib\VC\arm64\MD (not directly under lib) |
DLL load failed: The specified procedure could not be found |
OpenSSL in System32 is loaded first | Set up sitecustomize.py in Step 6 |
AuthorizationPermissionMismatch |
RBAC role not granted or waiting for propagation | Set up RBAC and wait a few minutes before retrying |
OpenSSL 3's legacy provider failed to load |
Warning only. No impact on operation | You can ignore it |
error: can't find Rust compiler |
Rust not installed or PATH not set | Perform Step 1 and restart the terminal |
FAQ
Q. Is this procedure necessary when deploying to Azure App Service?
No, it is not. Python on Azure App Service typically runs on Linux (x64 / ARM64), so pre-built wheels are automatically installed from PyPI. Even for Windows App Service, wheels are available since it is an x64 environment. This procedure is only necessary for local development on Windows ARM64.
Q. If I close the terminal after building, do I have to rebuild next time?
No, it is not. The built wheel is saved in the pip cache. The next time you run pip install cryptography, it will be retrieved from the cache, so there is no need to rebuild the environment.
# Check the cache
pip cache list cryptography
Q. What happens if I create a new venv?
Building is not required as it will be retrieved from the cache with pip install cryptography. However, sitecustomize.py needs to be created for each venv.
Q. Can I avoid this procedure by using WSL2?
Yes. As mentioned in the "Introduction," Linux ARM64 wheels are available on Ubuntu in WSL2. If WSL2 is suitable for your use case, it is the simplest option. If you need PowerShell or a Windows native environment, please set it up using the procedure in this article.
Q. Will this become unnecessary if a Windows ARM64 wheel is added to PyPI for cryptography?
Yes. Once the cryptography team officially releases a Windows ARM64 wheel, this procedure will be completely unnecessary. This is being discussed in the pyca/cryptography GitHub Issues.
Summary
To use Python + Azure SDK on Windows ARM64, the following three steps are required:
- Prepare build tools (Rust + MSVC ARM64 + OpenSSL)
-
Build
cryptographyfrom source (Set environment variables →pip install --no-binary) -
Avoid DLL conflicts (Place
sitecustomize.py)
Once set up, the cache takes over, so subsequent pip install runs will work as usual.
With the spread of Copilot+ PCs, the number of developers on Windows ARM64 is expected to increase. I hope this article helps you overcome the hurdles of setting up your environment.
Verification Environment
| Item | Version |
|---|---|
| Verification Date | 2026-02-14 |
| OS | Windows 11 ARM64 (24H2) |
| Python | 3.12.10 (ARM64) |
| cryptography | 46.0.5 (Source build) |
| Rust | 1.93.1 (aarch64-pc-windows-msvc) |
| MSVC | 14.44.35207 |
| OpenSSL | 3.6.1 (ShiningLight ARM64 Dev) |
| azure-identity | 1.25.2 |
| azure-storage-blob | 12.28.0 |
Discussion