<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harsh Trivedi</title>
    <description>The latest articles on DEV Community by Harsh Trivedi (@harsh_trivedi).</description>
    <link>https://dev.to/harsh_trivedi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4106529%2F8e0b1dc5-0426-424f-8106-d55062d8aa07.png</url>
      <title>DEV Community: Harsh Trivedi</title>
      <link>https://dev.to/harsh_trivedi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harsh_trivedi"/>
    <language>en</language>
    <item>
      <title>Azure Function App Stuck on "Runtime Unreachable"? How VNet Integration and Private Endpoints Fixed It</title>
      <dc:creator>Harsh Trivedi</dc:creator>
      <pubDate>Sat, 12 Sep 2026 17:43:28 +0000</pubDate>
      <link>https://dev.to/harsh_trivedi/azure-function-app-stuck-on-runtime-unreachable-how-vnet-integration-and-private-endpoints-fixed-2f39</link>
      <guid>https://dev.to/harsh_trivedi/azure-function-app-stuck-on-runtime-unreachable-how-vnet-integration-and-private-endpoints-fixed-2f39</guid>
      <description>&lt;p&gt;A beginner-friendly, real-world walkthrough of diagnosing and fixing networking issues in a Linux Azure Function App running on Elastic Premium.&lt;/p&gt;




&lt;p&gt;When an Azure Function App doesn't even show its runtime version, it is very easy to start looking at the application code.&lt;br&gt;
But what if you haven't deployed any code yet?&lt;/p&gt;

&lt;p&gt;That was exactly the situation I faced while setting up a new Linux Azure Function App on the Elastic Premium EP1 plan in Microsoft Azure. The Azure Portal could not properly load the runtime information, and ZIP deployment was failing before giving us any useful application-level logs.&lt;/p&gt;

&lt;p&gt;There was no Python code to debug.&lt;/p&gt;

&lt;p&gt;That was the first important clue.&lt;/p&gt;

&lt;p&gt;The problem was not in the application. It was in the networking and storage connectivity required by the Function App itself.&lt;/p&gt;

&lt;p&gt;The final solution involved connecting the Function App to the correct Virtual Network (VNet) and then creating a separate Private Endpoint and Private DNS configuration for another storage account used by the application.&lt;/p&gt;

&lt;p&gt;This article explains what happened, why it happened, and how to troubleshoot similar problems step by step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmezmkz4vh6d2gftw8qg3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmezmkz4vh6d2gftw8qg3.png" alt="Azure function app runtime fix error" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Architecture We Were Working With
&lt;/h2&gt;

&lt;p&gt;The environment was not a completely public Azure setup.&lt;/p&gt;

&lt;p&gt;The Function App was running on Linux + Azure Functions Elastic Premium (EP1), and the environment already had a shared VNet containing private resources.&lt;/p&gt;

&lt;p&gt;The storage account associated with the Function App was also protected by network restrictions and was reachable through private networking.&lt;/p&gt;

&lt;p&gt;Few existing Function App was already working in this environment.&lt;/p&gt;

&lt;p&gt;The new Function App, however, was not connected to the same VNet.&lt;/p&gt;

&lt;p&gt;That small difference was enough to prevent the new Function App from reaching the storage it needed.&lt;/p&gt;

&lt;p&gt;Azure Functions depends on storage for important runtime and application operations. For Premium plans, Azure Files is also commonly used for function app content and deployment-related functionality. Microsoft specifically notes that the storage account used by a Function App must be accessible to the app, and that Premium plans can use Azure Files for function code and configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So the important question became:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the storage account is private, how is the Function App supposed to reach it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer is through the VNet.&lt;/p&gt;


&lt;h2&gt;
  
  
  The First Problem: "Runtime Unreachable"
&lt;/h2&gt;

&lt;p&gt;Immediately after creating the Function App, we noticed a few unusual things.&lt;/p&gt;

&lt;p&gt;The Azure Portal couldn't properly display the Functions runtime version. The host appeared unreachable, and ZIP deployment was failing without giving us the kind of application logs we would normally expect.&lt;/p&gt;

&lt;p&gt;At first, this can be confusing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You might think:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Is function_app.py wrong?&lt;br&gt;
Is requirements.txt missing something?&lt;br&gt;
Is the Python version incorrect?&lt;br&gt;
Did the ZIP package have the wrong structure?&lt;/p&gt;

&lt;p&gt;But none of those explanations made sense because the application hadn't even been deployed yet.&lt;/p&gt;

&lt;p&gt;That changes the troubleshooting approach. If the Function App cannot initialize its host before your code is running, you should first investigate the infrastructure it depends on.&lt;/p&gt;

&lt;p&gt;One of the most important dependencies is storage.&lt;/p&gt;

&lt;p&gt;Azure Functions uses the storage account configured for the Function App for core operations. On Elastic Premium, Azure Files and queues can also be used to store application content and configuration. Microsoft documents AzureWebJobsStorage as the default storage connection and WEBSITE_CONTENTAZUREFILECONNECTIONSTRING as the storage connection used for Azure Files content on Elastic Premium and Consumption plans.&lt;/p&gt;

&lt;p&gt;In our environment, this storage account was protected by network restrictions and had a private endpoint. Existing Function Apps could access it because those Function Apps had already been integrated with the correct VNet.&lt;/p&gt;

&lt;p&gt;The new Function App wasn't.&lt;/p&gt;

&lt;p&gt;So we had a simple mismatch:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private storage → VNet access required → new Function App wasn't connected to the VNet.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  VNet Integration: What Does It Actually Do?
&lt;/h2&gt;

&lt;p&gt;This is one of the concepts that can be confusing when you are new to Azure networking.&lt;/p&gt;

&lt;p&gt;VNet integration is primarily an outbound networking feature.&lt;/p&gt;

&lt;p&gt;It gives the Function App a path into a VNet so that the app can reach resources inside that network, including resources exposed through private endpoints. It does not mean that your Function App suddenly becomes privately accessible from the VNet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;These are two different concepts:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;VNet Integration controls how the Function App makes outbound connections.&lt;/p&gt;

&lt;p&gt;Private Endpoint gives an Azure resource a private IP address inside a VNet.&lt;/p&gt;

&lt;p&gt;Microsoft's documentation specifically describes regional VNet integration as an outbound capability that allows Azure Functions to access resources in the VNet, including private endpoints.&lt;/p&gt;

&lt;p&gt;That distinction becomes extremely important when troubleshooting.&lt;/p&gt;


&lt;h2&gt;
  
  
  The First Fix: Connect the Function App to the VNet
&lt;/h2&gt;

&lt;p&gt;The easiest way to understand the required configuration was to look at the existing Function App that was already working. We checked its networking configuration and identified the VNet and the subnet used for VNet integration.&lt;/p&gt;

&lt;p&gt;Then we configured the new Function App using the same network architecture.&lt;/p&gt;

&lt;p&gt;From the Azure Portal, go to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Function App → Networking → Virtual Network Integration&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then select Add virtual network integration.&lt;/p&gt;

&lt;p&gt;Choose the VNet used by the existing application and select the dedicated integration subnet, if in your case no such VNet exist, then create a VNet first.&lt;/p&gt;

&lt;p&gt;For an Elastic Premium Linux Function App, the integration subnet must be delegated to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Microsoft.Web/serverFarms&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Microsoft currently documents /28 as the minimum subnet size for Elastic Premium VNet integration and recommends a larger subnet for Linux Premium workloads, because each running instance consumes an IP address and scaling can temporarily require additional addresses. You can also keep the default size when you setup the subnet.&lt;/p&gt;

&lt;p&gt;One important rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not use your private-endpoint subnet as the Function App integration subnet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These subnets have different purposes.&lt;/p&gt;

&lt;p&gt;The integration subnet is used by the Function App for VNet integration.&lt;/p&gt;

&lt;p&gt;The private-endpoint subnet contains the private IP addresses assigned to private endpoints.&lt;/p&gt;

&lt;p&gt;Microsoft's own Function App networking samples use separate subnets for these two purposes.&lt;/p&gt;

&lt;p&gt;Once the integration was completed, the Function App was restarted.&lt;/p&gt;

&lt;p&gt;After giving Azure a few minutes to complete the networking changes, the Function runtime became accessible again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That was a strong indication that we had identified the first problem correctly.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  But Then We Found Another Problem
&lt;/h2&gt;

&lt;p&gt;Getting the Function App runtime working was only the first part. The application also needed to communicate with another storage account. This was not the storage account used by the Function App itself.&lt;/p&gt;

&lt;p&gt;It was a separate business-content storage account used by the application to store processed documents.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Example scenerio- *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You have a task that triggers the function app on a specific time to place a file from an API to your blob storage account. Now this storage account is not the same that the function app uses.&lt;br&gt;
We had a simple health-check function that tested connectivity to different dependencies.&lt;/p&gt;

&lt;p&gt;The Key Vault check was successful.&lt;/p&gt;

&lt;p&gt;The Blob Storage check was failing.&lt;/p&gt;

&lt;p&gt;The error looked similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed to resolve 'contentarchive.blob.core.windows.net'
No address associated with hostname

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This error was extremely useful. Why?&lt;/p&gt;

&lt;p&gt;Because it wasn't an authentication error.&lt;/p&gt;

&lt;p&gt;It wasn't saying:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AuthorizationPermissionMismatch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It wasn't saying:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;403 Forbidden
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was saying that the hostname could not be resolved.&lt;/p&gt;

&lt;p&gt;That pointed us toward DNS and private endpoint configuration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why VNet Integration Didn't Automatically Fix the Second Storage Account
&lt;/h2&gt;

&lt;p&gt;This is another important concept. Connecting your Function App to a VNet does not automatically give the Function App private connectivity to every Azure resource.&lt;/p&gt;

&lt;p&gt;The destination resource must also be configured correctly.&lt;/p&gt;

&lt;p&gt;In our case, the second storage account did not yet have the required private endpoint.&lt;/p&gt;

&lt;p&gt;So we effectively had this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Function App
     |
     | VNet Integration
     ↓
   VNet
     |
     X
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Private path to content storage didn't exist&lt;br&gt;
The solution was to create the private networking path for that specific storage account.&lt;/p&gt;


&lt;h2&gt;
  
  
  Private Endpoint: What Does It Do?
&lt;/h2&gt;

&lt;p&gt;A Private Endpoint creates a private network interface with a private IP address inside your VNet and connects that IP to a specific Azure service.&lt;/p&gt;

&lt;p&gt;For example, if you create a Blob private endpoint for a storage account, the Blob service becomes reachable through a private IP.&lt;/p&gt;

&lt;p&gt;But there is an important detail here:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Private endpoints are tied to a specific service sub-resource.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For Azure Storage, Blob, File, Queue, Table, and other services have separate endpoints and corresponding DNS zones.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Blob  → privatelink.blob.core.windows.net
File  → privatelink.file.core.windows.net
Queue → privatelink.queue.core.windows.net
Table → privatelink.table.core.windows.net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Microsoft's current private endpoint documentation confirms these service-specific DNS zones.&lt;/p&gt;

&lt;p&gt;So creating a Blob private endpoint doesn't automatically create private connectivity for Azure Files or Queue.&lt;/p&gt;

&lt;p&gt;This distinction matters particularly for Function Apps because the Function runtime and the application itself may use different storage services.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Second Fix: Create a Private Endpoint for the Content Storage
&lt;/h2&gt;

&lt;p&gt;We opened the business-content storage account and went to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Networking → Private Endpoint Connections&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then we created a new private endpoint.&lt;/p&gt;

&lt;p&gt;For the target sub-resource, we selected:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Blob&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We selected the same VNet used by the Function App, but importantly, we selected the private-endpoint subnet, not the Function App's integration subnet.&lt;/p&gt;

&lt;p&gt;During the configuration, we also enabled integration with a Private DNS Zone.&lt;/p&gt;

&lt;p&gt;For Azure Blob Storage, the standard private DNS zone is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;privatelink.blob.core.windows.net&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Microsoft recommends this naming convention for Blob private endpoints.&lt;/p&gt;

&lt;p&gt;Once the private endpoint was provisioned and the connection was approved, the next step was verifying DNS.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why DNS Was So Important
&lt;/h2&gt;

&lt;p&gt;Creating a private endpoint gives the service a private IP. But your application doesn't normally connect to the storage account by typing its private IP.&lt;/p&gt;

&lt;p&gt;It still uses the normal hostname:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contentarchive.blob.core.windows.net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The job of Private DNS is to make that hostname resolve to the correct private endpoint.&lt;/p&gt;

&lt;p&gt;Conceptually, we want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contentarchive.blob.core.windows.net
                    ↓
        Private DNS resolution
                    ↓
             Private IP
                    ↓
          Private Endpoint
                    ↓
          Storage Account
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without the correct DNS configuration, the application might continue trying to resolve the hostname through the normal public DNS path—or fail to resolve it in the private networking context.&lt;/p&gt;

&lt;p&gt;Microsoft specifically states that applications calling private endpoints must have DNS resolution configured so the service hostname resolves to the private endpoint.&lt;/p&gt;




&lt;h2&gt;
  
  
  Checking the Private DNS Zone
&lt;/h2&gt;

&lt;p&gt;After creating the private endpoint, we checked:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private DNS Zones → privatelink.blob.core.windows.net&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Inside the zone, we checked the record sets.&lt;/p&gt;

&lt;p&gt;There should be an A record for the storage account that points to the private endpoint's IP address.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contentarchive
      ↓
10.x.x.x

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact IP will obviously be different in every environment.&lt;/p&gt;

&lt;p&gt;We then compared that address with the private IP assigned to the private endpoint.&lt;/p&gt;

&lt;p&gt;The addresses should match.&lt;/p&gt;

&lt;p&gt;We also checked the Virtual Network Links section.&lt;/p&gt;

&lt;p&gt;The VNet used by the Function App must be linked to the Private DNS Zone so that workloads inside that VNet can resolve the private name.&lt;/p&gt;

&lt;p&gt;Microsoft's DNS documentation describes the use of Private DNS Zones and VNet links for private endpoint name resolution.&lt;/p&gt;

&lt;p&gt;One more useful detail is that when a private endpoint is created with the recommended DNS zone configuration, Azure can automatically manage the corresponding private DNS record through the private endpoint's DNS zone group.&lt;/p&gt;




&lt;h2&gt;
  
  
  Restart and Test Again
&lt;/h2&gt;

&lt;p&gt;Once the networking and DNS configuration was complete, we restarted the Function App.&lt;/p&gt;

&lt;p&gt;Then we ran the health-check function again.&lt;/p&gt;

&lt;p&gt;The result changed from a DNS failure to a successful Blob connection.&lt;/p&gt;

&lt;p&gt;A simplified version of the health-check response looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "checks": {
    "key_vault": {
      "ok": true
    },
    "blob": {
      "ok": true
    }
  },
  "overall_ok": true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where health checks become extremely useful.&lt;/p&gt;

&lt;p&gt;Instead of simply knowing that "the Function isn't working," we can test individual dependencies.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Function App
    |
    +---- Key Vault      → OK
    |
    +---- Blob Storage   → DNS failure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After fixing DNS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Function App
    |
    +---- Key Vault      → OK
    |
    +---- Blob Storage   → OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That tells us much more about where the problem actually exists.&lt;/p&gt;




&lt;h2&gt;
  
  
  An Important Troubleshooting Pattern
&lt;/h2&gt;

&lt;p&gt;There is a useful pattern to remember when troubleshooting private networking.&lt;/p&gt;

&lt;p&gt;If you see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed to resolve hostname
No address associated with hostname
DNS resolution failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;start by investigating DNS and private endpoint configuration.&lt;/p&gt;

&lt;p&gt;If DNS starts working but you then receive something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;403 Forbidden
AuthorizationPermissionMismatch
Network access denied
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that is actually progress.&lt;/p&gt;

&lt;p&gt;It means the application can now find the destination, but something else is blocking the request.&lt;/p&gt;

&lt;p&gt;At that point, investigate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage firewall and network rules&lt;/li&gt;
&lt;li&gt;Private endpoint approval&lt;/li&gt;
&lt;li&gt;Identity or access permissions&lt;/li&gt;
&lt;li&gt;Storage RBAC&lt;/li&gt;
&lt;li&gt;Connection configuration&lt;/li&gt;
&lt;li&gt;The specific Storage service being accessed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is much more effective than changing application code randomly.&lt;/p&gt;




&lt;h2&gt;
  
  
  One Storage Account Does Not Mean One Private Endpoint
&lt;/h2&gt;

&lt;p&gt;This is probably the most important lesson from the second issue.&lt;/p&gt;

&lt;p&gt;Suppose your architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Function App
      |
      ↓
     VNet
      |
      +---- Storage Account A
      |
      +---- Storage Account B
      |
      +---- Key Vault
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You cannot assume that because Storage Account A has a private endpoint, Storage Account B is automatically private.&lt;/p&gt;

&lt;p&gt;Each Azure resource needs its own private connectivity configuration.&lt;/p&gt;

&lt;p&gt;And even within one Storage Account, different services can have different private endpoint requirements.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Storage Account
      |
      +---- Blob → Blob private endpoint
      |
      +---- File → File private endpoint
      |
      +---- Queue → Queue private endpoint

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact configuration depends on which services your Function App actually uses.&lt;/p&gt;

&lt;p&gt;This is particularly important for Azure Functions because the Function App's own storage requirements may include Azure Files in Elastic Premium, while your application may separately access Blob Storage for business data.&lt;/p&gt;




&lt;h2&gt;
  
  
  What About ZIP Deployment?
&lt;/h2&gt;

&lt;p&gt;Once the networking problem was fixed, deployment could be investigated separately.&lt;/p&gt;

&lt;p&gt;For a Python Function App, the ZIP package needs to contain the required project files at the root of the package.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function_app.py
host.json
requirements.txt

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important point is that host.json should be at the root of the extracted deployment package.&lt;/p&gt;

&lt;p&gt;For Linux Function Apps using remote build, Microsoft currently documents these application settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SCM_DO_BUILD_DURING_DEPLOYMENT=true
ENABLE_ORYX_BUILD=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remote build allows Azure to build dependencies in the target Linux environment rather than relying on packages built on your local machine.&lt;/p&gt;

&lt;p&gt;This is a deployment concern, though—not something to troubleshoot first when the Function host itself cannot start because it cannot reach its required storage.&lt;/p&gt;

&lt;p&gt;That distinction saved us a lot of unnecessary debugging.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Troubleshooting Flow I Would Follow Next Time
&lt;/h2&gt;

&lt;p&gt;If I encounter a new Function App that is unreachable before any application code has been deployed, I would follow this order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, check the Function App itself&lt;/strong&gt;&lt;br&gt;
Confirm that the Function App is running, the hosting plan is correct, and the runtime configuration is present.&lt;/p&gt;

&lt;p&gt;If the runtime itself cannot load, don't immediately start debugging function_app.py.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next, check the storage dependency&lt;/strong&gt;&lt;br&gt;
Look at the Function App's storage configuration, including AzureWebJobsStorage and, for Elastic Premium, the Azure Files content configuration where applicable.&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can this Function App actually reach the storage account it depends on?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the storage account is publicly accessible, the problem may be elsewhere.&lt;/p&gt;

&lt;p&gt;If it is restricted to a VNet or private endpoint, networking becomes a primary suspect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then, check VNet integration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Verify that the Function App is integrated with the correct VNet.&lt;/p&gt;

&lt;p&gt;Also verify that the integration subnet is separate from the private-endpoint subnet and has the correct delegation.&lt;/p&gt;

&lt;p&gt;For Elastic Premium Linux, Microsoft documents Microsoft.Web/serverFarms as the required delegation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then, check the private endpoint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For every private Azure service the application needs to access, verify that the appropriate private endpoint exists and is approved.&lt;/p&gt;

&lt;p&gt;Don't assume that another resource's private endpoint covers it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then, check DNS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make sure the correct Private DNS Zone exists and is linked to the VNet.&lt;/p&gt;

&lt;p&gt;For Blob Storage, that means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;privatelink.blob.core.windows.net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify that the storage account has the expected A record pointing to the private endpoint IP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finally, test the application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the infrastructure is confirmed, run a small health check that tests dependencies individually.&lt;/p&gt;

&lt;p&gt;That gives you a much clearer picture than testing the entire application at once.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Checklist
&lt;/h2&gt;

&lt;p&gt;When troubleshooting an Azure Function App that cannot reach a private storage account, I would check these in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Function App storage: Is the storage account used by the Function App accessible from the Function App's network path?&lt;/li&gt;
&lt;li&gt;VNet integration: Is the Function App connected to the correct VNet?&lt;/li&gt;
&lt;li&gt;Integration subnet: Is the correct dedicated subnet being used and delegated to Microsoft.Web/serverFarms for Elastic Premium?&lt;/li&gt;
&lt;li&gt;Private endpoint: Does the destination storage account have the required private endpoint for the service being accessed?&lt;/li&gt;
&lt;li&gt;Subnet separation: Is the private endpoint using its own subnet rather than the Function App's integration subnet?&lt;/li&gt;
&lt;li&gt;Private DNS: Does the appropriate Private DNS Zone exist and is it linked to the VNet?&lt;/li&gt;
&lt;li&gt;DNS record: Does the storage account hostname resolve to the private endpoint's IP?&lt;/li&gt;
&lt;li&gt;Access permissions: Once networking works, does the Function App have the required identity/RBAC or other authentication permissions?&lt;/li&gt;
&lt;li&gt;Deployment: Only after the platform and network are healthy, investigate ZIP packaging, dependencies, and remote build configuration.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;The following Microsoft Learn resources were used to verify the Azure networking and deployment concepts discussed in this article:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-networking-options?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Azure Functions networking options&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/el-gr/azure/azure-functions/storage-considerations?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Storage considerations for Azure Functions&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/azure//private-link/private-endpoint-dns?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Azure Private Endpoint DNS configuration&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-create-vnet?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Use private endpoints to integrate Azure Functions with a virtual network&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-deployment-technologies?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Deployment technologies in Azure Functions&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/run-functions-from-deployment-package?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Run your Functions from a Package File in Azure&lt;/a&gt;&lt;/p&gt;

</description>
      <category>azurefunctions</category>
      <category>azure</category>
      <category>functionapp</category>
      <category>errorfix</category>
    </item>
    <item>
      <title>Solving the Background Verification Bottleneck for enterprises: Inside BGVerifyIQ</title>
      <dc:creator>Harsh Trivedi</dc:creator>
      <pubDate>Thu, 03 Sep 2026 03:20:11 +0000</pubDate>
      <link>https://dev.to/harsh_trivedi/solving-the-background-verification-bottleneck-for-enterprises-inside-bgverifyiq-l94</link>
      <guid>https://dev.to/harsh_trivedi/solving-the-background-verification-bottleneck-for-enterprises-inside-bgverifyiq-l94</guid>
      <description>&lt;p&gt;Imagine an HR manager who has just completed this month’s hiring drive. Dozens of candidates have accepted their offers, and everyone is eager to onboard them as quickly as possible. But before that can happen, every background verification request has to move through multiple checks, vendors, approvals, and status updates. What should be a straightforward operational process often turns into hours of chasing spreadsheets, checking vendor portals, and answering the same status questions over and over again. It isn’t a technology problem as much as it is a visibility problem — and that’s the challenge that inspired BGVerifyIQ.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkyphqea2sce4rs3olhua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkyphqea2sce4rs3olhua.png" alt="BGVerify Platform architecture" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem every HR team quietly struggles with
&lt;/h2&gt;

&lt;p&gt;Ask any HR or Talent Acquisition team what happens after an offer letter goes out, and you’ll hear a familiar story. A candidate is selected. A background verification (BGV) request is raised with a vendor. And then… the waiting begins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behind that wait is a surprising amount of manual work:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HR has to log into multiple vendor portals just to check where a case stands.&lt;/li&gt;
&lt;li&gt;Status updates live in scattered Excel sheets, emails, and vendor dashboards that rarely agree with each other.&lt;/li&gt;
&lt;li&gt;Nobody has a single, live number for “how many candidates are actually ready to be approved today.”&lt;/li&gt;
&lt;li&gt;SLA breaches — cases that have been open too long — get discovered late, usually when a hiring manager complains.&lt;/li&gt;
&lt;li&gt;When a discrepancy or a “suspect” flag shows up, it can get buried in a spreadsheet row instead of being escalated immediately.&lt;/li&gt;
&lt;li&gt;Every time leadership asks “how are our BGV vendors performing,” someone spends half a day pulling numbers together manually.&lt;/li&gt;
&lt;li&gt;New joiners get onboarded before their verification is even reviewed properly, simply because nobody had a clear, current view of their case.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this is because HR teams aren’t diligent. It’s because the tools weren’t built for this specific job. Spreadsheets don’t talk to vendor systems. Vendor portals don’t talk to each other. And nobody has time to become a SQL expert just to answer a simple question like “which candidates are stuck.”&lt;/p&gt;

&lt;p&gt;This is the exact gap BGVerifyIQ was built to close.&lt;/p&gt;




&lt;h2&gt;
  
  
  What BGVerifyIQ actually does
&lt;/h2&gt;

&lt;p&gt;BGVerifyIQ is a single workspace that sits on top of your background verification data — requests, checks, education records, employment records — and gives HR three things they didn’t have before, all in one place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A plain-English way to ask questions, without writing a single line of SQL.&lt;/li&gt;
&lt;li&gt;A live, always-current dashboard of the entire BGV pipeline — no manual pulling of numbers.&lt;/li&gt;
&lt;li&gt;A complete 360° view of any single candidate, with a clear, explainable recommendation on whether they’re ready to be approved.&lt;/li&gt;
&lt;li&gt;Everything in the current version is intentionally read-only. It never changes your underlying data. It only helps people see it, understand it, and act on it faster. That’s an important design decision we’ll come back to later.&lt;/li&gt;
&lt;/ul&gt;


&lt;div&gt;
    &lt;iframe src="https://www.youtube.com/embed/BuAX8R8UJPg" width="315" height="560"&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;





&lt;h2&gt;
  
  
  Why I didn’t just build “another chatbot”
&lt;/h2&gt;

&lt;p&gt;There’s a lot of excitement right now about AI agents that can answer any question in a chat window. And that excitement is well placed — for the right kind of question.&lt;/p&gt;

&lt;p&gt;But here’s the catch: a chat window is great when you have a specific question (“what’s the status of candidate Ananya?”). It’s a poor way to see the big picture (“how many candidates are pending across all vendors right now, broken down by how old each case is?”). Nobody wants to type ten different questions into a chatbot every morning just to get their daily overview.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;So instead of picking one or the other, BGVerifyIQ combines both, deliberately, as separate pages built for separate jobs:&lt;br&gt;
*&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat — for quick, specific, in-the-moment questions.&lt;/li&gt;
&lt;li&gt;KPI Dashboard — for the daily/weekly bird’s-eye view, the numbers leadership actually cares about.&lt;/li&gt;
&lt;li&gt;Candidate 360 — for a deep dive into one candidate before making an approval decision.&lt;/li&gt;
&lt;li&gt;History — because past answers and past conversations shouldn’t disappear the moment you close the tab.&lt;/li&gt;
&lt;li&gt;Settings — so each user can control their own experience and see exactly which AI models are answering their questions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This “agent + dashboard” hybrid is, in our view, the right shape for most internal business tools going forward. The agent handles the ad hoc and the unexpected. The dashboard handles the routine and the recurring. Neither replaces the other.&lt;/p&gt;


&lt;h2&gt;
  
  
  A tour of the app
&lt;/h2&gt;

&lt;p&gt;💬** Chat**&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjk1m8iciy1tnphw48b1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjk1m8iciy1tnphw48b1p.png" alt="BGVerify IQ chat page" width="720" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiiz5o8b7sj20coarfu71.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiiz5o8b7sj20coarfu71.png" alt="chat page 2" width="640" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where a user can type something like “show me approval-ready candidates” or “any updates on Rao” in completely normal English. Behind the scenes, the question is turned into a safe, read-only database query, run against the data, and answered with a short summary plus the actual table of results underneath — so nothing is ever “just trust the AI,” the numbers are right there to verify.&lt;/p&gt;

&lt;p&gt;Three quick-action buttons — Priority Queue, SLA Breaches, Vendor Performance — skip the AI translation step entirely and jump straight to pre-built, always-correct answers for the questions people ask most often. Every question and every answer is automatically saved, so nothing is lost.&lt;/p&gt;



&lt;p&gt;📊 &lt;strong&gt;KPI Dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbrcuaonn43dq3vxf2l8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbrcuaonn43dq3vxf2l8k.png" alt="KPI Dashboard page" width="640" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the “morning coffee” page — a live, numbers-first view of the entire BGV pipeline: total requests, how many are cleared, how many are pending, and how many have a major discrepancy. It also shows a status breakdown, how long cases have been open (aging buckets), how each vendor is performing on turnaround time, and — critically — a live list of every case currently breaching its SLA.&lt;/p&gt;

&lt;p&gt;At the bottom sits the Priority Queue: a ranked list of exactly which candidates need attention today, downloadable as a CSV for anyone who wants to share it further.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbfzrkrtwg60ag8klqok6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbfzrkrtwg60ag8klqok6.png" alt="Background verification KPI page" width="640" height="308"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;👤 &lt;strong&gt;Candidate 360&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2qwj54erim133l25vwqy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2qwj54erim133l25vwqy.png" alt="BGVerifyIQ Candidate 360 page" width="640" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Search for any candidate by name or ID, and this page pulls together everything known about them into one screen: overall status, an approval-readiness badge, a risk score, the assigned vendor and vendor contact, a check-by-check breakdown (education, employment, address, criminal, identity), a dated timeline of everything that’s happened on the case, and — importantly — a plain-English explanation of why the system is recommending “Ready,” “Caution,” “Needs Review,” or “Escalate.” This isn’t a black-box score; every recommendation comes with the specific reasons behind it, so HR can trust it and defend the decision if asked.&lt;/p&gt;

&lt;p&gt;From here, HR can download a one-page PDF report or email it directly to a hiring manager or stakeholder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi3oqxrlpbbk9h7aypx8l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi3oqxrlpbbk9h7aypx8l.png" alt="Candidate 360 page" width="640" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbqixomgmmxybc3o027be.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbqixomgmmxybc3o027be.png" alt="Candidate 360 page email" width="640" height="315"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;🕘 &lt;strong&gt;History&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhjiow1qvpy7qw7s6z4ff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhjiow1qvpy7qw7s6z4ff.png" alt="History chat page" width="640" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every past conversation from the Chat page, tied to the logged-in user’s email, searchable by keyword, newest first. Click “Open” on any past conversation and it reloads right back into Chat so the person can keep going from where they left off.&lt;/p&gt;



&lt;p&gt;⚙️ &lt;strong&gt;Settings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgtj5w8n6wtqwcpjjt4za.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgtj5w8n6wtqwcpjjt4za.png" alt="settings page" width="640" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Users can update their name, role, and email, switch between light and dark theme, and — importantly for trust and transparency — see exactly which AI model is currently answering their questions, and confirm that the system is running in read-only mode.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;About&lt;/strong&gt;&lt;br&gt;
This section explains what each page is about and what BGVerifyIQ stands for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzjorpwqbrimxi8uimup8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzjorpwqbrimxi8uimup8.png" alt="About page" width="640" height="307"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Dark Mode&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqkr2ud9o26g5aeqx29lb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqkr2ud9o26g5aeqx29lb.png" alt="BGVerifyIQ platform dark mode" width="640" height="305"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What’s happening behind the scenes
&lt;/h2&gt;

&lt;p&gt;For the developers and technical stakeholders reading this, here’s a quick look at how the current version is built, and why each piece exists.&lt;br&gt;
db.py — handles the connection to the PostgreSQL database. It reads connection details from environment variables (so nothing sensitive is hard-coded), keeps one reusable connection pool for performance, and includes a small but important safety function: is_read_only_sql(). This function checks every single query before it's allowed to run, and blocks anything that isn't a plain SELECT. It's the guardrail that makes it safe to let an AI generate SQL on the fly — even if the AI ever tried to write something destructive, this layer would refuse it.&lt;/p&gt;

&lt;p&gt;llm.py — the AI layer that turns a plain-English question into a safe SQL query, and turns raw query results back into a clear, professional summary. It's built so that if one AI provider is slow or down, it automatically falls back to a second one — so the app doesn't just stop working during a demo or a busy morning. It also carries strict rules about how to match candidate names and IDs (using flexible partial matching instead of exact matches, since people rarely type a name or ID perfectly), which is a big part of why the Chat page actually finds what users are looking for instead of returning "no results."&lt;/p&gt;

&lt;p&gt;pdf_report.py — generates the one-page Candidate 360 PDF on demand, entirely in memory, with careful handling so that special characters (like smart quotes or long names) never break the PDF layout.&lt;/p&gt;

&lt;p&gt;mailer.py — sends the PDF report directly to a stakeholder's inbox. Worth noting: this file also tells a useful real-world lesson. It was originally built using standard SMTP email sending, which worked perfectly on a local machine, but failed once deployed to a cloud platform — because most cloud hosting providers block outbound SMTP traffic to prevent spam abuse. The fix was to switch to a transactional email API (Brevo) that works over regular HTTPS, which is never blocked. It's a small example of the kind of real infrastructure problem that only shows up once you actually deploy something.&lt;/p&gt;

&lt;p&gt;The data layer — a clean PostgreSQL schema (bgv) with tables for requests, checks, education, and employment history, plus three pre-built views (v_candidate_360, v_sla_breaches, v_vendor_performance) that do the heavy lifting of joining and aggregating data. The AI is instructed to always prefer these views over writing its own joins — which keeps its answers consistent and correct.&lt;/p&gt;


&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A live version of BGVerifyIQ is deployed and ready to explore:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://bgverifyiq-production.up.railway.app/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;bgverifyiq-production.up.railway.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7tgbiyp57qa1tuontyv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7tgbiyp57qa1tuontyv0.png" alt="BGVerifyIQ landing page" width="640" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to click through every page — Chat, KPI Dashboard, Candidate 360, History, and Settings — with sample data already loaded, so you can see exactly how it behaves before considering it for your own team.&lt;/p&gt;




&lt;h2&gt;
  
  
  From prototype to enterprise: what a real rollout looks like
&lt;/h2&gt;

&lt;p&gt;What’s described above is a working, functional prototype — and a genuinely useful one. But there’s an honest and important distinction between “a tool that solves the problem well for a demo or a small team” and “a tool that’s ready to run background verification for thousands of employees across an entire organization.” Here’s what that jump actually involves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A production-grade frontend&lt;/strong&gt;&lt;br&gt;
The current interface is built using Streamlit, which is excellent for proving out an idea fast. For an organization-wide rollout, this would typically move to a proper frontend framework — Angular, React, or similar — giving finer control over performance, accessibility, custom branding, and integration with existing internal design systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A real backend, with security built in from day one&lt;/strong&gt;&lt;br&gt;
An enterprise version needs a proper backend service layer, not just a script talking to a database. That means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Authentication — logging in through the company’s existing identity provider (SSO/SAML/Azure AD), not a name-and-email form.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Authorization — making sure a regional HR analyst can only see their region’s candidates, while a compliance officer might see everything, and a vendor SPOC sees only their own cases. Not everyone should see everyone’s data. Basically Role Based Access Control, data masking policies should be enabled. [We will discuss both RBAC and Data Masking in snowflake in another article]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data security — encryption of data at rest and in transit, strict handling of personally identifiable information (PII), and audit logs of who viewed or changed what, and when.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proper exception handling — every failure (a database timeout, an AI provider being slow, a malformed input) should fail gracefully with a clear message, never a broken page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Testing — automated tests for the business rules (like the risk-scoring and readiness logic), so a future code change can’t silently break how a candidate gets flagged.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A feedback mechanism — a simple way for HR users to flag when an AI-generated answer was wrong or unhelpful, so the system keeps improving based on real usage instead of guesswork.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Using AI models your organization already trusts and governs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is one of the most important points for any organization considering this seriously.&lt;/p&gt;

&lt;p&gt;The current prototype uses free, hosted, general-purpose AI models (Groq’s Llama model, and Google’s Gemini, as a backup). These are great for building and proving out an idea quickly — but they were not built or contracted for handling real, sensitive employee data such as names, ID numbers, addresses, and background check outcomes. An organization should not send real employee records to a public, general-purpose AI API unless that API is specifically covered by the company’s data processing agreements and security review.&lt;/p&gt;

&lt;p&gt;The right approach for a real deployment is to use whatever AI platform your organization has already vetted and governs — most companies today are standardized on either Snowflake or Databricks for their data warehouse, and both now offer their own governed AI agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your organization’s data lives in Snowflake, you can use Snowflake Cortex Agents to run directly on your existing tables and views — the exact same bgv schema and views shown above would work almost as-is. The AI never leaves Snowflake's security boundary, meaning your data doesn't get sent to an outside company's servers at all.&lt;/li&gt;
&lt;li&gt;If your organization uses Databricks, the same idea applies with Databricks’ Mosaic AI agents running on your Lakehouse tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Beyond just being safer, these governed platforms typically unlock more capability too — automatically generating charts, producing longer comparative analyses (“compare this quarter’s vendor turnaround to last quarter”), and integrating with the rest of your company’s existing data and security tooling, rather than living as a separate, isolated app.&lt;/p&gt;

&lt;p&gt;In short: build and prove the idea with free/open tools first (as I did here), then swap in your organization’s approved, governed AI platform before any real employee data touches it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Additional functionality worth adding
&lt;/h2&gt;

&lt;p&gt;Once the security and governance foundation is in place, a few natural next features come to mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A CRUD page to approve or update candidate status directly from the app — instead of just viewing data, an authorized HR user could mark a candidate as approved, add a remark, or update a case status, with that change written straight back to the source system, fully audit-logged.&lt;/li&gt;
&lt;li&gt;Notifications — automatic alerts (email, Slack, Teams) the moment a case breaches SLA or a suspect flag appears, instead of HR having to go looking for it.&lt;/li&gt;
&lt;li&gt;Integration with the HRMS/ATS — so a “Ready” status in BGVerifyIQ can automatically trigger the next onboarding step, instead of someone manually copying that status elsewhere.&lt;/li&gt;
&lt;li&gt;Feedback and continuous improvement loop — letting users rate AI answers, which helps refine the system over time.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why an AI agent at all — and why it matters even more on mobile
&lt;/h2&gt;

&lt;p&gt;It’s worth pausing on this, because “just add an AI chatbot” can sound like a trend rather than a real solution. Here’s the actual problem an agent solves.&lt;/p&gt;

&lt;p&gt;Traditionally, if an HR analyst wanted to answer a slightly unusual question — “how many campus hires are stuck with a discrepancy this month?” — they had one of two options: ask someone technical to write a query for them, or manually filter and cross-reference spreadsheets by hand. Both are slow, and both mean the person asking the question depends on someone else, or on their own patience with Excel.&lt;/p&gt;

&lt;p&gt;An AI agent removes that dependency. It lets someone simply ask, in their own words, and get a trustworthy, data-backed answer in seconds — without needing to know what a database even is. That’s the real value: it turns “I need to go find someone who can pull this” into “I just asked, and I have my answer.”&lt;/p&gt;

&lt;p&gt;This matters even more on mobile. A dashboard with charts and tables is genuinely hard to use well on a small phone screen — things get cramped, and scrolling through filters is painful. A chat interface, on the other hand, is something almost everyone is already completely comfortable with, because it looks and feels exactly like every messaging app they already use. On a phone, “just type your question” is a far better experience than “pinch and zoom into a dashboard.” This is a big part of why the agent and the dashboard are built as complementary tools rather than the dashboard being the only option — mobile users, in particular, benefit enormously from being able to just ask.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this actually solves — the short version
&lt;/h2&gt;

&lt;p&gt;For organization leaders and executives, here’s the summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Saves time — no more logging into multiple vendor portals or manually cross-referencing spreadsheets to answer a simple status question.&lt;/li&gt;
&lt;li&gt;Faster approvals — a clear, explainable readiness badge tells HR exactly who’s ready to move forward, and why, without second-guessing.&lt;/li&gt;
&lt;li&gt;Fewer surprises — SLA breaches and risk flags are surfaced automatically and immediately, instead of being discovered weeks later.&lt;/li&gt;
&lt;li&gt;Less repetitive manual work — one-click PDF reports and direct email delivery replace manually compiling updates for hiring managers.&lt;/li&gt;
&lt;li&gt;Better decisions, not just faster reports — the KPI dashboard turns raw data into visible bottlenecks and vendor performance trends that leadership can actually act on.&lt;/li&gt;
&lt;li&gt;A tool people will actually use — because it meets people where they already are, whether that’s a quick chat question on a phone or a full dashboard review on a desktop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And to be clear about where this stands today: this is proof that the idea works, built on real, functioning logic — the business rules, the read-only safety design, the recommendation logic — none of that is a mockup. What comes next, for an organization ready to roll this out at scale, is wrapping that same proven logic in enterprise-grade security, governance, and infrastructure — using AI models the organization already trusts with its data, not a public API.&lt;/p&gt;

&lt;p&gt;The underlying idea, though, doesn’t change: give HR one place to ask, one place to see, and one place to decide — instead of five different tools that don’t talk to each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftizv7glybiclcpwj3rax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftizv7glybiclcpwj3rax.png" alt="BGVerifyIQ summary" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  BGVerifyIQ assists decisions — final approval always rests with the HR team.
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;BGVerifyIQ is a demonstration project created to showcase how AI can streamline and improve the background verification process. All data, candidate names, organizations, vendors, and background verification records shown in the application are entirely fictional and generated for demonstration purposes. No real employee, customer, or organizational data has been used at any stage of development, testing, screenshots, or deployment.&lt;/p&gt;

&lt;p&gt;The application is built on a carefully designed sample dataset that simulates realistic background verification scenarios while ensuring privacy and confidentiality.&lt;/p&gt;

&lt;p&gt;If you have questions about the architecture, implementation, AI workflow, or would like to discuss how a similar solution could be built for your organization, I’d be happy to connect. Feel free to reach out through LinkedIn or leave a comment on this article, and I’ll do my best to help.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>hr</category>
      <category>enterpriseai</category>
    </item>
    <item>
      <title>Securing Enterprise AI Pipelines: Using Azure Key Vault and AES Encryption for Sensitive Documents in Snowflake/Databricks AI Workloads</title>
      <dc:creator>Harsh Trivedi</dc:creator>
      <pubDate>Wed, 02 Sep 2026 17:03:05 +0000</pubDate>
      <link>https://dev.to/harsh_trivedi/securing-enterprise-ai-pipelines-using-azure-key-vault-and-aes-encryption-for-sensitive-documents-565a</link>
      <guid>https://dev.to/harsh_trivedi/securing-enterprise-ai-pipelines-using-azure-key-vault-and-aes-encryption-for-sensitive-documents-565a</guid>
      <description>&lt;p&gt;A practical architecture for securing contracts, invoices, employee data, and business documents before they are consumed by AI models, document intelligence systems, and enterprise agents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2wmsiyrcxlaxv1h0fspq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2wmsiyrcxlaxv1h0fspq.png" alt="enterprise ai pipeline" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Organizations are rapidly building AI-powered applications on top of business documents such as contracts, invoices, employee records, financial reports, sales data, and operational data. While significant effort is spent on developing AI models and intelligent agents, security is often treated as an afterthought.&lt;/p&gt;

&lt;p&gt;One of the biggest risks in enterprise AI is exposing sensitive information during document storage, processing, and retrieval. Simply storing files in cloud storage or data platforms is not enough. The data should also be secured during transmission.&lt;/p&gt;

&lt;p&gt;In this article, I will walk you through a security-first architecture that combines AES encryption, Azure Key Vault, Service Principals, RBAC permissions, and controlled decryption workflows to protect sensitive documents while still enabling AI-powered document extraction, analytics, and intelligent agents.&lt;br&gt;
We’ll cover:&lt;/p&gt;

&lt;p&gt;✔ The security problem enterprises face&lt;/p&gt;

&lt;p&gt;✔ Why encrypted storage alone is not enough&lt;/p&gt;

&lt;p&gt;✔ Why encryption keys should never be stored in code or .env files&lt;/p&gt;

&lt;p&gt;✔ Azure Key Vault fundamentals&lt;/p&gt;

&lt;p&gt;✔ Service Principal authentication&lt;/p&gt;

&lt;p&gt;✔ RBAC permissions and access control&lt;/p&gt;

&lt;p&gt;✔ Creating and managing Key Vault secrets&lt;/p&gt;

&lt;p&gt;✔ Python implementation examples&lt;/p&gt;

&lt;p&gt;✔ Snowflake and Databricks integration patterns&lt;/p&gt;

&lt;p&gt;✔ Secure document processing for AI workloads&lt;/p&gt;

&lt;p&gt;✔ Security benefits and best practices&lt;/p&gt;

&lt;p&gt;This architecture can be applied across Snowflake, Databricks, Microsoft Fabric, Azure AI Foundry, Synapse Analytics, and custom AI platforms.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Growing Security Challenge in Enterprise AI
&lt;/h2&gt;

&lt;p&gt;Organizations are increasingly building AI applications on top of business-critical documents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples include:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Customer contracts&lt;/li&gt;
&lt;li&gt;Legal agreements&lt;/li&gt;
&lt;li&gt;Invoices&lt;/li&gt;
&lt;li&gt;Financial statements&lt;/li&gt;
&lt;li&gt;Employee records&lt;/li&gt;
&lt;li&gt;Payroll information&lt;/li&gt;
&lt;li&gt;Vendor documents&lt;/li&gt;
&lt;li&gt;HR reports&lt;/li&gt;
&lt;li&gt;Employee attrition predictions&lt;/li&gt;
&lt;li&gt;Compliance reports&lt;/li&gt;
&lt;li&gt;Healthcare records&lt;/li&gt;
&lt;li&gt;Procurement documents&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These documents often contain highly sensitive information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At the same time, organizations want AI systems to:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extract information from documents&lt;/li&gt;
&lt;li&gt;Build search experiences&lt;/li&gt;
&lt;li&gt;Power RAG solutions&lt;/li&gt;
&lt;li&gt;Support AI agents&lt;/li&gt;
&lt;li&gt;Generate business insights&lt;/li&gt;
&lt;li&gt;Answer natural language questions&lt;/li&gt;
&lt;li&gt;Generate KPIs, charts and visuals&lt;/li&gt;
&lt;li&gt;This creates a difficult challenge:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;How can we allow AI systems to use sensitive information without exposing the underlying documents?&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Wrong Approach
&lt;/h2&gt;

&lt;p&gt;Many organizations unknowingly introduce security risks by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storing documents unencrypted&lt;/li&gt;
&lt;li&gt;Storing encryption keys in source code or environment files&lt;/li&gt;
&lt;li&gt;Keeping secrets in configuration files&lt;/li&gt;
&lt;li&gt;Saving credentials inside notebooks&lt;/li&gt;
&lt;li&gt;Embedding keys inside ETL pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AES_KEY = "MySecretEncryptionKey"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If someone gains access to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub repositories&lt;/li&gt;
&lt;li&gt;DevOps pipelines&lt;/li&gt;
&lt;li&gt;Virtual machines&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;Storage accounts
they may gain access to both the encrypted documents and the encryption key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point, encryption provides little value.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Security Principle
&lt;/h2&gt;

&lt;p&gt;One of the most important security principles is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Encrypt the data and protect the encryption key separately.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even if attackers gain access to encrypted documents, they should not be able to access the encryption key.&lt;/p&gt;

&lt;p&gt;This is where Azure Key Vault becomes critical.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution Architecture
&lt;/h2&gt;

&lt;p&gt;The architecture consists of five major layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Document Encryption&lt;/li&gt;
&lt;li&gt;Secure Key Storage&lt;/li&gt;
&lt;li&gt;Controlled Authentication&lt;/li&gt;
&lt;li&gt;In-Memory Decryption&lt;/li&gt;
&lt;li&gt;AI Processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frbrp54md6frrcjuv2l0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frbrp54md6frrcjuv2l0r.png" alt="Solution architecture" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Document Source — The source of document can be anything like SAP, Cloud storage, Azure Blob Storage etc.&lt;/p&gt;

&lt;p&gt;When we move them to our storage layer, they should be encrypted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step implementation guide-
&lt;/h2&gt;

&lt;h2&gt;
  
  
  A) Why We Encrypt Documents
&lt;/h2&gt;

&lt;p&gt;Consider documents such as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client contracts&lt;/li&gt;
&lt;li&gt;Employee compensation data&lt;/li&gt;
&lt;li&gt;Vendor agreements&lt;/li&gt;
&lt;li&gt;Invoices&lt;/li&gt;
&lt;li&gt;Strategic business reports&lt;/li&gt;
&lt;li&gt;Attrition prediction outputs
These files often contain information that should not be accessible to every user or system.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before storing these files, we encrypt them using AES-256.&lt;/p&gt;

&lt;p&gt;This ensures that even if storage is compromised or a developer has RBAC (Role based access control), the document remains unreadable without the encryption key.&lt;/p&gt;




&lt;h2&gt;
  
  
  B) Creating an AES Encryption Key
&lt;/h2&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from Crypto.Random import get_random_bytes
AES-256 = 32 bytes
aes_key = get_random_bytes(32)
print(aes_key.hex()) 32 bytes = 256 bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates an AES-256 encryption key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AES?
&lt;/h2&gt;

&lt;p&gt;AES (Advanced Encryption Standard) is one of the most widely used symmetric encryption algorithms in the world.&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast&lt;/li&gt;
&lt;li&gt;Highly secure&lt;/li&gt;
&lt;li&gt;Industry standard&lt;/li&gt;
&lt;li&gt;Suitable for large documents&lt;/li&gt;
&lt;li&gt;Supported across cloud platforms
AES-256 is commonly used in enterprise environments.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  C) What is Azure Key Vault?
&lt;/h2&gt;

&lt;p&gt;Azure Key Vault is a managed Azure service designed for securely storing and controlling access to secrets, cryptographic keys, and certificates.&lt;/p&gt;

&lt;p&gt;Instead of storing sensitive values in application code, organizations place them inside a centralized vault protected by Azure Identity and RBAC controls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Azure Key Vault supports three primary object types:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secrets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API Keys&lt;/li&gt;
&lt;li&gt;Database Passwords&lt;/li&gt;
&lt;li&gt;OAuth Client Secrets&lt;/li&gt;
&lt;li&gt;AES Encryption Keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Keys&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RSA Keys&lt;/li&gt;
&lt;li&gt;Cryptographic Signing Keys&lt;/li&gt;
&lt;li&gt;Customer Managed Encryption Keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Certificates&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSL Certificates&lt;/li&gt;
&lt;li&gt;TLS Certificates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In our use case, the AES encryption key is stored as a Secret.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Azure Key Vault is required?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Centralized secret management&lt;/li&gt;
&lt;li&gt;Fine-grained access control&lt;/li&gt;
&lt;li&gt;Secret rotation support&lt;/li&gt;
&lt;li&gt;Access auditing&lt;/li&gt;
&lt;li&gt;Compliance support&lt;/li&gt;
&lt;li&gt;Reduced insider risk&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Creating Azure Key Vault
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.Navigate to: portal.azure.com&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Azure Portal -&amp;gt; Create Resource -&amp;gt; Key Vault -&amp;gt; Create&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;2.Configure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Subscription

Resource Group

Region (eg. Central India)

Vault Name (eg. projectname-aes-key-kv)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.For Authorization/Permission Model:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Select: Azure Role Based Access Control (RBAC)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;4.For Networking:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Public access: Selected networks

or

Private endpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.Permissions Required to Create a Key Vault&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Typically one of the following roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Owner&lt;/li&gt;
&lt;li&gt;Contributor&lt;/li&gt;
&lt;li&gt;Key Vault Contributor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Key Vault Contributor can manage the Key Vault resource itself but cannot read secrets stored within the vault.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This separation improves security.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;6.Storing the AES Key in key vault secrets and the permissions that are required to create secrets.&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
IMP: When using Azure RBAC, you will need Key Vault secret officer role to create secret.&lt;/p&gt;

&lt;p&gt;Once the role is assigned, Create and Store the generated AES key as a secret.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;Secret Name:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AES-DOCUMENT-ENCRYPTION-KEY : secret _code&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key is now centrally managed and protected.&lt;/p&gt;


&lt;h2&gt;
  
  
  D) Creating a Service Principal Applications, requires an identity to access Azure resources.
&lt;/h2&gt;

&lt;p&gt;This is where Service Principals are used.&lt;/p&gt;

&lt;p&gt;Think of a Service Principal as:&lt;/p&gt;

&lt;p&gt;A non-human identity used by applications.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Snowflake/Databricks/Azure Function/Fabric Pipeline/Custom API

↓

Service Principal

↓

Azure Key Vault

↓

AES Secret


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Service Principal becomes the trusted identity that accesses the vault.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Service Principals Are Important&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without Service Principals:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Applications would require user credentials&lt;/li&gt;
&lt;li&gt;Automation becomes difficult&lt;/li&gt;
&lt;li&gt;Auditing becomes harder&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Service Principals provide:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Automated authentication&lt;/li&gt;
&lt;li&gt;Secure access&lt;/li&gt;
&lt;li&gt;RBAC integration&lt;/li&gt;
&lt;li&gt;Least privilege access&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Required: The service principal system-managed identity must be assigned read secret role on the key vault&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For Snowflake, Databricks, Fabric, or AI platforms: (Your service principal name might be: projectname_aeskey_extract_spn)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assign Role:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Key Vault Secrets User&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read secret values&lt;/li&gt;
&lt;li&gt;Read secret metadata&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  E) Python Example: Reading the AES Key
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from azure.identity import ClientSecretCredential
from azure.keyvault.secrets import SecretClient
credential = ClientSecretCredential(
    tenant_id="&amp;lt;tenant-id&amp;gt;",
    client_id="&amp;lt;client-id&amp;gt;",
    client_secret="&amp;lt;client-secret&amp;gt;"
)
vault_url = "https://company-kv.vault.azure.net"
client = SecretClient(
    vault_url=vault_url,
    credential=credential
)
aes_key = client.get_secret(
    "AES-DOCUMENT-ENCRYPTION-KEY"
).value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application retrieves the key only when needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  F) Encrypting Sensitive Documents
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes
# AES key retrieved from Azure Key Vault
key = bytes.fromhex(aes_key_hex)
# Generate random IV (16 bytes for AES)
iv = get_random_bytes(16)
with open("contract.pdf", "rb") as file:
    plaintext = file.read()
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(
    pad(plaintext, AES.block_size)
)
# Store IV along with encrypted content
encrypted_content = {
    "iv": iv,
    "ciphertext": ciphertext
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The encrypted file can now be stored safely.&lt;/p&gt;




&lt;h2&gt;
  
  
  G) AI Processing Pattern
&lt;/h2&gt;

&lt;p&gt;When processing begins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve AES key from Key Vault&lt;/li&gt;
&lt;li&gt;Decrypt document in memory&lt;/li&gt;
&lt;li&gt;Extract structured or unstructured chunk information&lt;/li&gt;
&lt;li&gt;Persist extracted results&lt;/li&gt;
&lt;li&gt;Discard decrypted content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Decrypt only when required and only in memory.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  H) Platform Integration Examples
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjf91qxyb2023mhlt1c3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjf91qxyb2023mhlt1c3w.png" alt="Platform integration" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  I) AI Agents and RAG Systems
&lt;/h2&gt;

&lt;p&gt;Once document information is extracted into structured datasets, AI systems can answer questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which contracts expire next month?&lt;/li&gt;
&lt;li&gt;Which invoices exceed $100,000?&lt;/li&gt;
&lt;li&gt;Which vendors require renewal?&lt;/li&gt;
&lt;li&gt;What is the predicted attrition risk for the Sales department?&lt;/li&gt;
&lt;li&gt;Which customers have pending obligations?
The AI model operates on structured business data rather than unrestricted access to sensitive raw documents.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  J) Security Benefits Achieved
&lt;/h2&gt;

&lt;p&gt;This architecture provides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Encryption at Rest — Documents remain protected in storage.&lt;/li&gt;
&lt;li&gt;Key Separation — Encryption keys are separated from encrypted data.&lt;/li&gt;
&lt;li&gt;Least Privilege Access — Applications receive only required permissions.&lt;/li&gt;
&lt;li&gt;Auditing — Secret access can be monitored.&lt;/li&gt;
&lt;li&gt;Key Rotation — Encryption keys can be replaced centrally.&lt;/li&gt;
&lt;li&gt;Compliance Support — Supports enterprise governance and security requirements.&lt;/li&gt;
&lt;li&gt;Reduced Attack Surface — Compromised storage does not automatically expose sensitive information.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;As organizations accelerate AI adoption, securing the data feeding those AI systems becomes just as important as building the models themselves.&lt;/p&gt;

&lt;p&gt;A secure AI platform is not only about model accuracy, vector databases, or intelligent agents. It is equally about protecting contracts, invoices, employee information, and other sensitive business assets that power those systems.&lt;/p&gt;

&lt;p&gt;By combining AES encryption, Azure Key Vault, Service Principals, RBAC permissions, and controlled in-memory decryption, organizations can build AI platforms that are secure, scalable, compliant, and enterprise-ready.&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Protect the documents.&lt;br&gt;
Protect the keys.&lt;br&gt;
Allow AI access only when necessary.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What next?
&lt;/h2&gt;

&lt;p&gt;In my next article, I will walk you through how we implemented enterprise-grade access controls for AI-powered platforms using techniques such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Row-Level Security (RLS)&lt;/li&gt;
&lt;li&gt;Row Access Policies&lt;/li&gt;
&lt;li&gt;Dynamic Data Masking&lt;/li&gt;
&lt;li&gt;Role-Based Access Control (RBAC)&lt;/li&gt;
&lt;li&gt;Business Unit-based filtering&lt;/li&gt;
&lt;li&gt;Customer-based entitlements&lt;/li&gt;
&lt;li&gt;Financial data masking&lt;/li&gt;
&lt;li&gt;Secure document access controls&lt;/li&gt;
&lt;li&gt;Time-limited document download links&lt;/li&gt;
&lt;li&gt;Agent-level authorization patterns&lt;/li&gt;
&lt;li&gt;Governance frameworks for AI applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll explore how an AI agent can return different answers to different users for the same question, while ensuring that sensitive information remains protected and compliant with organizational policies.&lt;/p&gt;

&lt;p&gt;Because securing the documents is important.&lt;/p&gt;

&lt;p&gt;But securing who can access the information extracted from those documents is what truly makes an AI platform enterprise-ready.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>snowflake</category>
      <category>agents</category>
      <category>rag</category>
    </item>
  </channel>
</rss>
