Azure

Software Mile builds and runs applications on Microsoft Azure – for organizations already in the Microsoft ecosystem, or ones that want enterprise-grade cloud with the identity and compliance tooling Azure brings.

Where Azure Fits Best

  • App Service, Functions, and container apps for web and API workloads
  • Azure SQL, Cosmos DB, and managed data services
  • Entra ID (Azure AD) integration for enterprise identity and single sign-on
  • DevOps pipelines, infrastructure as code, and monitoring with Azure-native tooling

Azure shines when you are already running Microsoft 365 and want identity, security, and billing in one place. Tell us your workload and we will architect for it.

The Microsoft Shop Argument for Azure

It is a real argument. If your identity already lives in Entra ID, your procurement and support relationship is with Microsoft, and your developers write .NET, then Azure removes friction at every one of those points. Sign-on can reuse directory work you have already done, licensing sits on an agreement you already hold, and your team reads documentation in a stack they already know.

It is not, on its own, a reason to move a system that runs well somewhere else. Migration costs are paid up front and the savings stay theoretical until someone models them properly. If the driver is consolidating onto one vendor, that is a legitimate business decision, and it deserves to be argued as one.

App Service, Container Apps, Functions, or AKS?

Compute choice is where Azure projects tend to over-engineer themselves. Each option removes a different amount of work from your team, and the right answer is usually the least capable one that actually fits the workload. Starting simple leaves room to move up later; starting on a cluster you did not need means operating one from day one.

  • App Service. A web application or API that needs to run, scale, and be deployed. Least to operate, and enough for a wide range of ordinary workloads.
  • Container Apps. When you want containers and scale to zero without running a cluster, including background workers and event-driven jobs.
  • Functions. Event handlers, scheduled jobs, and glue between services. Weigh consumption-plan cold starts against always-warm options before putting a user-facing API on it.
  • AKS. Justified by scale, by specific Kubernetes requirements, or by existing Kubernetes skills. Chosen for other reasons, it becomes a second product to maintain.

Which Azure SQL Option Fits a Legacy Application?

The question is how much SQL Server surface area the application actually uses. Azure SQL Database asks the least of you operationally but does not offer everything an on-premises instance does, and applications built over many years often lean on cross-database queries, SQL Agent jobs, linked servers, or CLR without anyone remembering that they do.

Managed Instance exists precisely for that case and is usually the shorter path when lifting an established .NET application. SQL Server on a virtual machine remains the fallback when you need full control or a specific version, with the patching left to you. Auditing what the application depends on before choosing is a small piece of work that prevents a large surprise.

What Entra ID Actually Solves

Three things worth having: users sign in with the account they already have, access policy is enforced centrally and outside your application code, and services authenticate to each other using managed identities so connection strings and secrets stop living in configuration files. That last point closes one common route to credential leaks, though over-scoped or misconfigured identities remain your problem to manage.

The common surprise is organizational. App registrations, permissions, and conditional access policies are usually controlled by a security team, so this work is often blocked waiting on approvals and not on code. Find out early who grants what, and put the approval steps in the schedule alongside the engineering.

Where Does Azure Spend Get Away From You?

Cloud bills rarely grow because of one bad decision. They grow because nothing is ever switched off, sizing is never revisited, and no single person owns the total. The items below are worth reviewing on an established estate, and none of them require re-architecting anything.

  • Non-production environments running around the clock. Development and test resources used only in office hours can often be scheduled down, though reserved capacity and license floors can change the arithmetic.
  • Oversized service plans and databases. Sized against a launch-day estimate, never compared with actual load since.
  • Untagged resources. If cost cannot be attributed to a team or a system, nobody can be asked to reduce it.
  • Commitment options ignored. Steady workloads may come out lower on reservations or savings plans, and the comparison is easy to run and easy to never get around to.
  • Data movement and logging. Verbose diagnostics and cross-region traffic accumulate quietly and are usually easy to trim once someone looks.

VNet Integration, Private Endpoints, and Private DNS

Locking down an App Service or a Function App means two separate pieces of configuration, regional VNet integration and private endpoints, and the names do not make the difference obvious. Inbound and outbound are configured independently, so an application can reach a database over a private address while its own front door is still answering the public internet, or the reverse.

Creating a private endpoint adds a record in a private DNS zone such as privatelink.database.windows.net, and that record is what makes the resource's ordinary public hostname resolve to the private address from inside the virtual network. Clients outside that DNS scope keep resolving the public IP, which is why an identical connection string works from a VM in the VNet and times out from a laptop on VPN or from a server on-premises whose resolver never learned the zone. When something cannot connect, nslookup from the failing client is most of the diagnostic: a public IP in the answer is a DNS problem, a private IP with no connection is routing or a network security group.

  • Regional VNet integration. Outbound only. It gives the application a route into your virtual network so it can reach private addresses, and it requires a subnet delegated to it rather than shared with other resources.
  • Private endpoint. Inbound to a platform resource. A network interface in your subnet with a private IP, so traffic to that storage account, database, or key vault stays on the virtual network.
  • Service endpoint. Also inbound control, but no private IP. The resource keeps its public endpoint and limits access to traffic originating in named subnets. Simpler to configure, and it does nothing for traffic arriving from on-premises.
  • Access restrictions on the app itself. IP and service tag rules evaluated on inbound requests to App Service or Functions before your code runs. This is where public access to the application is closed, and the app can take a private endpoint of its own as well.

Deployment Slots and What a Swap Actually Does

Deployment slots are additional hostnames running on the same App Service plan, and that has an immediate consequence: the staging slot shares compute with production, so a load test against staging competes for the same CPU and memory as live traffic. The swap itself is a routing change rather than a deployment. The instance that ends up serving production is exactly the one that was already running in staging.

Application settings and connection strings follow the slot only when they are marked as slot settings. Anything not marked travels with the code during a swap, which is how a staging database connection string reaches production. The swap sequence also matters: Azure applies the target slot's settings to the source instance, restarts it, and waits for it to answer warmup requests, so the application boots once with production configuration while still in staging. Startup work that depends on configuration, such as running migrations or priming a cache, therefore executes against production before any traffic moves. Four other properties of slots decide whether they help or hurt.

  • Certificates and custom domains bind to a slot. The staging slot has its own hostname and needs its own binding if you intend to test TLS there.
  • The staging hostname is public unless you close it. It resolves on the internet like any other App Service hostname, so access restrictions or authentication belong on it too.
  • Function triggers fire in staging. A timer or queue trigger starts running as soon as the slot is configured, so a staging slot pointed at production queues processes real work before any swap happens.
  • Swapping back is also only a routing change. It restores which instance serves traffic and undoes nothing the new code already wrote to a database or a queue.

Zone Redundancy, Region Failure, and Backups Are Three Different Things

Availability zones are physically separate facilities within a single region, with independent power and cooling and low latency links between them. Zone redundancy is a property you opt into per resource: a zone-redundant App Service plan, a zone-redundant SQL database, a storage account created as ZRS. It covers the loss of one facility, it is invisible to your connection strings, and for several services it is set at creation, which means enabling it later is a redeployment rather than a setting change.

Backups answer a different question, the one where the infrastructure is healthy and something was deleted or corrupted. Azure SQL takes automatic backups and supports point-in-time restore within a retention window that defaults to seven days, with long-term retention as a separate setting. The restore produces a new database instead of overwriting the original, so the application still has to be pointed at it. Geo-redundant storage copies blobs to a paired region, which protects against losing the bytes and not against a deployment that overwrote them, unless soft delete or versioning is on.

A region failure is the case neither of those covers. Recovering from one means having somewhere else to run, which is a design decision with a standing cost attached rather than a switch to flip. Active-passive with a warm standby, active-active behind a global front end, and restoring from backup into another region after the fact are all defensible answers, but they carry different budgets and different recovery times, and describing all three as disaster recovery is how a plan gets approved without being real. Whichever one is chosen, a second region has to account for four things.

  • The application itself. Compute in the second region, deployed by the same pipeline, or the standby drifts until the day it is needed.
  • Secrets and certificates. Key Vault is a regional resource. TLS certificates, connection strings, and signing keys have to exist in the second region before the failure, not during it.
  • Data and static content. Geo-replication for the database, and whatever the storage replication setting actually is rather than what it was assumed to be. Read access to a secondary copy is not automatic.
  • Traffic steering. Front Door or Traffic Manager decides where requests land. Traffic Manager operates at the DNS layer, so client and resolver caching stretches the cutover well past the moment the health probe notices.

Managed Identity Failures and How to Tell Them Apart

A managed identity gets its token from a local endpoint on the host, the instance metadata service on a VM and an environment-provided endpoint on App Service and Functions, which means that code path only exists when the code runs in Azure. DefaultAzureCredential in the Azure SDKs walks a chain of sources and falls back to the developer's signed-in Azure CLI or IDE account, so the same code authenticates on a laptop and fails after deployment. Running the cloud path in a deployed environment early, rather than at release, is what keeps that from being discovered late.

The failures are easy to separate once you read the whole response instead of the status code. A 403 means a token was issued and the role assignment is missing or scoped elsewhere, most often assigned at the resource group when the resource needed it or assigned to a similarly named resource in another environment. A failure to acquire a token at all means the identity is not enabled on the host, or that several user-assigned identities are attached and no client ID was specified, leaving the runtime unable to choose. Assignments are not instant either: a new one takes time to propagate, and tokens already issued keep their old claims until they expire.

Key Vault adds one more branch. Access to a vault is governed either by its own access policies or by Azure RBAC, depending on how the vault was created, and a correctly scoped role assignment has no effect on a vault still running access policies. Checking which permission model the vault uses comes before debugging anything else.

Subscriptions, Resource Groups, and the Choices You Cannot Undo

Scope in Azure is a hierarchy: management group, subscription, resource group, resource. A role assigned at any level applies to everything beneath it, which is why an access review that only inspects assignments on a resource misses everyone holding Owner on the subscription. Quotas mostly sit at the subscription and region level, including vCPU counts per VM family, so a deployment can fail for capacity reasons that have nothing to do with the template being wrong.

A resource group is a deletion and deployment boundary, not a security perimeter on its own. Deleting one deletes everything inside it. Its location stores only its metadata, so it can hold resources in other regions. Moving resources between groups or subscriptions is supported for many resource types and not for all, and the types that cannot move have to be recreated at the destination.

Two decisions are effectively permanent. A resource's region is fixed at creation, so moving to another region means deploying new resources and migrating data rather than changing a setting. And several names are globally unique across all of Azure, including storage account names and the default azurewebsites.net hostname, which is why the naming convention is worth settling before the first environment exists rather than after three of them do.

Frequently Asked Questions

Is Azure the wrong choice for some projects?

Yes, in two situations that have nothing to do with comparing platforms. Workloads that have to sit next to equipment belong at the site, where processing survives the loss of an internet connection and the round trip to a region is not in the control path, with the cloud used for aggregation and management instead. The second is when the expectation is that Azure fixes the application. Hosting changes where code runs, not how it is written, so a slow query, an in-process design that blocks scaling out, and a release process nobody trusts all arrive intact.

What does Azure manage, and what stays ours?

Azure operates the hardware, the hypervisor, and for platform services the operating system underneath. Everything above that is yours: the language runtime version the application targets, its libraries, the access configuration, and whether backups are actually enabled and have been restored at least once. App Service publishes end of support dates for language runtimes, and an app pinned past one generally keeps running while no longer receiving fixes, which is why runtime upgrades belong on a schedule rather than in an incident.

What has to exist on our side before Azure work can begin?

A Microsoft Entra tenant and at least one subscription with a billing arrangement behind it. The rest is people rather than resources: someone with authority to assign roles and to create or consent to app registrations, and someone accountable for the bill who can approve SKU decisions. You also need control of the DNS zone for any custom domain, since domain verification and certificate issuance both work by adding records to it.

Can Azure connect to systems we keep on-premises?

Yes, at three levels of commitment. A site-to-site IPsec VPN over the public internet is the usual starting point and needs a compatible device and a public IP at your end. ExpressRoute is a private circuit through a provider, with a higher cost and more predictable latency. Where a single application needs to reach a single internal host, Hybrid Connections use an agent inside your network that opens an outbound TCP relay on 443, leaving inbound firewall rules alone. Whichever you pick, plan name resolution in both directions at the same time, because conditional forwarders are the piece that gets discovered late.

How does a migration to Azure actually proceed?

The order that avoids rework is inventory first, foundation second, workload third. Inventory means a dependency map: what calls what, which outbound addresses third parties have allowlisted, and which scheduled jobs exist and where they run today. The foundation is the subscription layout, networking, identity, and deployment pipeline, built once and reused. Only then does a workload move, usually with the database replicating ahead of time so the cutover itself is short. Lower the DNS TTL on every record involved days before the cutover, not on the day.

What do we have to decide rather than delegate?

Region and data residency, recovery objectives, and how many environments you are willing to run. These are business constraints rather than technical preferences: the recovery point and recovery time you can accept determine the replication and standby design, and answering zero to both has a price attached. Residency also narrows the options, since not every service and SKU is available in every region. The environment count matters because each one has to be built and maintained by the same pipeline, and collapsing to a single shared environment moves the risk into releases.

How much of an Azure design is portable if we leave later?

Some of it, and the split is worth knowing at design time rather than at exit time. A containerized application, a SQL Server or PostgreSQL database, and blob storage kept behind a repository interface move with moderate effort. Functions with platform triggers and bindings, the Cosmos DB data model, authorization built on Entra ID, and Bicep or ARM templates are specific to Azure and get rewritten. Neither choice is automatically wrong, but the cost of leaving is set by how many of the second group you use.