In this post we are going to cover security and access control for ADLS Gen2 and Blob Storage. These are 7 real ADLS Gen2 and Blob Storage interview questions for data engineers, asked the way they come up on a real project, and the last one is a scenario: finance data must be visible only to finance, while the data team manages the whole lake.
Access control decides who can read, write or manage data in a storage account. There are a few layers: how a client proves who it is (account keys, SAS tokens or Microsoft Entra ID), which roles it has (Azure RBAC), and folder-level permissions (ACLs). Interviewers ask about it because a leaked key or a too-wide role is one of the most common real incidents in a data lake.
Part 4 of the Real Time Azure Data Lake Storage Interview Questions and Answers series on TechBrothersIT.
- The short answer
- Let's set up the project
- Question 1: Leadership asks how applications should authenticate to storage. Account keys, SAS or Microsoft Entra ID?
- Question 2: A pipeline needs access with no secrets in code. How do managed identities and storage roles work?
- Question 3: Someone asks the difference between Azure RBAC and ACLs in ADLS Gen2. When do you use each?
- Question 4: A partner needs to upload files for one day only. How do you give them a SAS safely?
- Question 5: A teammate asks about user delegation SAS versus account SAS. Which is safer and why?
- Question 6: Someone asks how ACL inheritance works for new files and folders. What are default ACLs?
- Scenario 7: Finance data must be visible only to finance, while the data team manages the whole lake. How do you secure it?
- The full script
The short answer
Use Microsoft Entra ID with managed identities and data roles (Storage Blob Data Reader / Contributor / Owner), and turn Shared Key off. RBAC is checked first; ACLs add folder-level access and can't take away a role. For outsiders, a short, least-privilege user delegation SAS.
Let's set up the project
We run everything against Azurite, Microsoft's open-source Azure Storage emulator, running locally, with small Python scripts that use the azure-storage-blob client and pyarrow. Features the emulator does not support, such as Microsoft Entra ID, the hierarchical namespace and ACLs, are shown as code. Every script imports common.py, which connects to the account, creates a container on first use and prints errors in a short form.
import os
import textwrap
from azure.storage.blob import BlobServiceClient
svc = BlobServiceClient.from_connection_string(
os.environ["AZURE_STORAGE_CONNECTION_STRING"])
def container(name):
"""Get a container client, creating the container on first use."""
c = svc.get_container_client(name)
if not c.exists():
c.create_container()
return c
def show_err(e):
code = getattr(e.error_code, "value", e.error_code)
print(" ", type(e).__name__, e.status_code, code)
first = str(e).split("\n")[0] # first line, wrapped
print(textwrap.fill(first, 62, initial_indent=" ",
subsequent_indent=" "))Question 1: Leadership asks how applications should authenticate to storage. Account keys, SAS or Microsoft Entra ID?
Microsoft Entra ID, wherever the client supports it. An account key is effectively super-user access to the whole account, and a service or account SAS is signed with it. Entra ID gives each app its own identity, with no secret to leak.
| Method | What it is | Use it for |
|---|---|---|
| Account key (Shared Key) | super-user on the whole account | nothing new: turn it off |
| Service or account SAS | a token signed with the account key | legacy only |
| User delegation SAS | signed with an Entra delegation key, 7 days max | short external access |
| Microsoft Entra ID | an identity per app, with Azure RBAC and ACLs | apps and people: the default |
Let's see why keys worry me. We run python keys.py. It uses the account key to list containers and read the finance ledger, then tries an old key after a rotation.
import os
from azure.core.exceptions import HttpResponseError
from azure.storage.blob import BlobServiceClient
from common import svc, container, show_err
container("finance").upload_blob("gl/2026/10/gl.csv",
b"account,amount\n4000,1250.00\n",
overwrite=True)
container("sales").upload_blob("2026/10/30/orders.csv",
b"order_id,amount\n1001,25.50\n",
overwrite=True)
print("account key lists:", [c.name for c in svc.list_containers()])
gl = svc.get_blob_client("finance", "gl/2026/10/gl.csv")
row = gl.download_blob().readall().split(b"\n")[1]
print("account key reads:", row)
conn = os.environ["AZURE_STORAGE_CONNECTION_STRING"]
old = conn.replace(svc.credential.account_key, # rotated away
"b2xkLWtleS1iZWZvcmUtcm90YXRpb24tMDAwMDAwMDA=")
app = BlobServiceClient.from_connection_string(old)
try:
list(app.list_containers())
except HttpResponseError as e:
print("old key after rotation:"); show_err(e)$ python keys.py
account key lists: ['finance', 'sales']
account key reads: b'4000,1250.00'
old key after rotation:
HttpResponseError 403 AuthorizationFailure
Server failed to authenticate the request. Make sure the
value of the Authorization header is formed correctly
including the signature.With the account key, the client lists ['finance', 'sales'] and reads b'4000,1250.00' from the ledger. No role and no ACL is checked. After the rotation, the app holding the old key is locked out. The emulator answers 403 AuthorizationFailure; on Azure the code is AuthenticationFailed.
So the target is Entra ID for apps and people, a user delegation SAS for short external access, and Shared Key off. That rejects account keys and key-signed SAS, while a user delegation SAS keeps working.
az storage account update -n stshoplake -g rg-lake \
--allow-shared-key-access falseBefore you turn it off, check who still uses keys in the blob logs, filtered by authentication type:
// Who still uses keys or key-signed SAS? (blob logs)
StorageBlobLogs
| where TimeGenerated > ago(30d)
| where AuthenticationType in ("AccountKey", "SAS")
| summarize requests = count()
by AuthenticationType, CallerIpAddress
| order by requests descSkip that log check, and you break someone's job at night.
Question 2: A pipeline needs access with no secrets in code. How do managed identities and storage roles work?
A managed identity is a Microsoft Entra identity that Azure gives the resource itself, like a Data Factory or a Databricks access connector. Azure manages its credentials, so the code holds only the account URL.
Let's follow the flow. First, Data Factory runs with its managed identity, with no secret. Then Microsoft Entra ID issues a token. Then the storage account checks the data role.
In Python, the client takes DefaultAzureCredential instead of a key. On Azure it picks up the managed identity; on a laptop, the developer's own sign-in. Same code, no secret. The emulator has no Entra ID, so this is code.
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
URL = "https://stshoplake.blob.core.windows.net"
svc = BlobServiceClient(URL, credential=DefaultAzureCredential())
# Azure: the managed identity; laptop: your developer sign-in
# production: AZURE_TOKEN_CREDENTIALS=prod skips developer logins
curated = svc.get_container_client("curated")
for name in curated.list_blob_names(name_starts_with="sales/"):
print(name)Then we grant a data role, scoped tight: one container if you can.
ACCT=$(az storage account show -n stshoplake -g rg-lake \
--query id -o tsv)
az role assignment create \
--assignee-object-id <adf-managed-identity-object-id> \
--assignee-principal-type ServicePrincipal \
--role "Storage Blob Data Contributor" \
--scope "$ACCT/blobServices/default/containers/curated"Here is what each data role can do:
| Data role | Can |
|---|---|
| Storage Blob Data Reader | read and list |
| Storage Blob Data Contributor | also write and delete |
| Storage Blob Data Owner | also manage all ACLs |
Two traps. Management roles like Owner or Contributor on the account give no data access, but they can read the keys. And new role assignments can take up to 10 minutes to apply.
I grant roles to groups and pipeline identities, not to people, and keep them in Bicep or Terraform.
Question 3: Someone asks the difference between Azure RBAC and ACLs in ADLS Gen2. When do you use each?
RBAC assigns roles at a scope: subscription, resource group, account or container. ACLs are POSIX-like permissions on each directory and file, and they need the hierarchical namespace.
| Azure RBAC | ACLs | |
|---|---|---|
| Scope | subscription, resource group, account, container | each directory and file |
| Needs | any storage account | hierarchical namespace (ADLS Gen2) |
| Grants | built-in data roles | r, w, x per user, group or identity |
| Limit | 4,000 role assignments per subscription | 32 entries per file or directory |
The order matters. Let's follow a request to read finance/gl.csv. First, Azure checks role assignments. If a role grants the access, it is allowed and ACLs are not checked. Only when no role grants it does the ACL decide. So an ACL can never take away access that a role grants.
That is how I split the work:
- RBAC: broad access, like the data team on whole containers.
- ACLs: folder-level access inside a container, like one team's folder.
- Entra groups, not users: there are 32 ACL entries per file or directory, for access and default ACLs each.
- Execute on every parent: to read a file, every parent folder needs execute.
The emulator has no hierarchical namespace, so ACLs are shown as code later in this post.
Storage Blob Data Reader on the account, then surprise that the finance folder's ACL stops nobody. The role beats any ACL.
Question 4: A partner needs to upload files for one day only. How do you give them a SAS safely?
Least privilege and a short life:
- One container:
partner-drop, nothing else. - Create and write only: no read, no list, no delete.
- Expires in one day: a short life limits a leak.
- HTTPS only: plus an IP range if the partner has fixed addresses.
Let's test it. We run python partner_sas.py. It creates a SAS on partner-drop with create and write only, for one day, uploads a file with it, tries to read it back, and then tries an upload with a SAS that has already expired.
from datetime import datetime, timedelta, timezone
from azure.core.exceptions import HttpResponseError
from azure.storage.blob import (ContainerClient,
ContainerSasPermissions, generate_container_sas)
from common import svc, container, show_err
def partner_client(expiry):
sas = generate_container_sas(
svc.account_name, "partner-drop",
account_key=svc.credential.account_key,
permission=ContainerSasPermissions(create=True, write=True),
expiry=expiry) # sp=cw: no read, no list
return ContainerClient.from_container_url(
f"{svc.url}partner-drop?{sas}")
container("partner-drop")
now = datetime.now(timezone.utc)
partner = partner_client(now + timedelta(days=1)) # one day only
partner.upload_blob("2026-10-30/stock.csv", b"sku,qty\nA1,5\n")
print("upload: ok")
try:
partner.download_blob("2026-10-30/stock.csv").readall()
except HttpResponseError as e:
print("read back:"); show_err(e)
expired = partner_client(now - timedelta(minutes=5)) # the day after
try:
expired.upload_blob("2026-10-31/stock.csv", b"sku,qty\nA1,4\n")
except HttpResponseError as e:
print("upload with an expired SAS:"); show_err(e)$ python partner_sas.py
upload: ok
read back:
HttpResponseError 403 AuthorizationPermissionMismatch
This request is not authorized to perform this operation
using this permission.
upload with an expired SAS:
HttpResponseError 403 AuthorizationFailure
Server failed to authenticate the request. Make sure the
value of the Authorization header is formed correctly
including the signature.The upload prints upload: ok. Reading the file back fails with 403 AuthorizationPermissionMismatch, because the token has no read permission. The day after, the expired token is rejected with 403 AuthorizationFailure. That is the emulator's code; on Azure it is AuthenticationFailed, and the detail names the expiry.
On Azure, I sign it as a user delegation SAS: no account key, and it works with Shared Key off. The emulator has no Entra ID and doesn't enforce IP ranges, so that version stays in code.
from datetime import datetime, timedelta, timezone
from azure.identity import DefaultAzureCredential
from azure.storage.blob import (BlobServiceClient,
ContainerSasPermissions, generate_container_sas)
svc = BlobServiceClient("https://stshoplake.blob.core.windows.net",
credential=DefaultAzureCredential())
now = datetime.now(timezone.utc)
key = svc.get_user_delegation_key(now, now + timedelta(days=1))
sas = generate_container_sas(
"stshoplake", "partner-drop", user_delegation_key=key,
permission=ContainerSasPermissions(create=True, write=True),
expiry=now + timedelta(days=1), protocol="https",
ip="203.0.113.0-203.0.113.255") # partner's fixed rangeThe drop container is a quarantine. Partners only write there, and a pipeline validates each file before it moves into the lake.
Question 5: A teammate asks about user delegation SAS versus account SAS. Which is safer and why?
User delegation SAS, and Microsoft recommends it. It is signed with a delegation key that an Entra identity requests, can't grant more than that identity has, and lives at most 7 days. An account SAS is signed with the account key and can cover the whole account.
| User delegation SAS | Account SAS | |
|---|---|---|
| Signed with | a delegation key requested with Entra ID | the account key |
| Permissions | never more than the signing identity has | whatever the token grants |
| Covers | Blob Storage: a container, blob or directory | one or more services, the whole account |
| Lifetime | 7 days at most | no hard limit: set an expiration policy |
| Revoke | revoke delegation keys, or remove the role | rotate the signing key |
| Shared Key off | keeps working | rejected |
Let's look at the blast radius. We run python account_sas.py. It creates one account SAS with read and list, uses it across the account, tries to create a container, and then asks for a user delegation key with the account key.
from datetime import datetime, timedelta, timezone
from azure.core.exceptions import HttpResponseError
from azure.storage.blob import (AccountSasPermissions,
BlobServiceClient, ResourceTypes, generate_account_sas)
from common import svc, show_err
now = datetime.now(timezone.utc)
sas = generate_account_sas(
svc.account_name, svc.credential.account_key,
resource_types=ResourceTypes(service=True, container=True,
object=True),
permission=AccountSasPermissions(read=True, list=True),
expiry=now + timedelta(hours=8))
reader = BlobServiceClient(svc.url, credential=sas)
print("account SAS lists:",
[c.name for c in reader.list_containers()])
gl = reader.get_blob_client("finance", "gl/2026/10/gl.csv")
row = gl.download_blob().readall().split(b"\n")[1]
print("account SAS reads:", row)
try:
reader.create_container("scratch")
except HttpResponseError as e:
print("create container:"); show_err(e)
try: # needs a Microsoft Entra token
svc.get_user_delegation_key(now, now + timedelta(hours=8))
except HttpResponseError as e:
print("user delegation key with the account key:"); show_err(e)$ python account_sas.py
account SAS lists: ['finance', 'partner-drop', 'sales']
account SAS reads: b'4000,1250.00'
create container:
HttpResponseError 403 AuthorizationPermissionMismatch
This request is not authorized to perform this operation
using this permission.
user delegation key with the account key:
ClientAuthenticationError 403 AuthenticationFailed
Server failed to authenticate the request. Make sure the
value of the Authorization header is formed correctly
including the signature.The account SAS lists ['finance', 'partner-drop', 'sales'], finance included, and reads the ledger, b'4000,1250.00'. Its permissions still hold: creating a container fails with 403 AuthorizationPermissionMismatch. And the user delegation key request is rejected with ClientAuthenticationError 403 AuthenticationFailed, because it needs an Entra token, which this setup lacks.
Revocation differs too. An account SAS stays valid until it expires or its signing key is rotated. A user delegation SAS stops when you revoke the delegation keys or remove the signer's role.
I also set a SAS expiration policy on the account, so long-lived tokens show up in the logs.
Question 6: Someone asks how ACL inheritance works for new files and folders. What are default ACLs?
A directory has two ACLs. The access ACL controls the directory itself. The default ACL is a template: each new child gets its access ACL from it. Files have no default ACL.
Let's walk through the finance/ folder, which has an access ACL and a default ACL:
- A new folder like
gl/2026/11/gets an access ACL and a default ACL from it. - A new file gets an access ACL only.
- An existing folder like
gl/2026/10/stays unchanged.
So on the finance folder, I add read and execute for the finance group, as an access entry and a default entry. The catch is that a changed default ACL doesn't touch children that already exist, so I apply it with update-recursive, which fixes the folder and everything already under it. The emulator has no hierarchical namespace, so this is code.
G=<finance-group-object-id>
# access entry: the folder itself; default entry: new children
az storage fs access update-recursive \
--account-name stshoplake --auth-mode login \
--file-system lake --path finance \
--acl "group:$G:r-x,default:group:$G:r-x"
# recursive: also fixes every item that already existsThree details to remember:
- List a folder:
r-xon it. - Reach a file:
--xon every parent. - Parent without a default ACL: the umask
007applies, nothing for other.
I set default ACLs for groups when I create the zone folders, before the first file lands.
Scenario 7: Finance data must be visible only to finance, while the data team manages the whole lake. How do you secure it?
Separate by container. Finance data gets its own container, the finance Entra group gets Storage Blob Data Reader on that container only, and the finance pipeline's managed identity gets Contributor there.
| Who | Role | Scope |
|---|---|---|
| Finance analysts (Entra group) | Storage Blob Data Reader | finance container |
| Finance pipeline (managed identity) | Storage Blob Data Contributor | finance container |
| Data team (Entra group) | Storage Blob Data Owner | raw, sales and curated containers |
| Data team (Entra group) | Contributor (management) | the storage account |
| Everyone | Shared Key access | turned off |
The data team runs the lake with a management role on the account and data roles on the other containers. The trap: management roles can read the keys, and a key reads finance. So Shared Key is off, and I keep it off with an Azure Policy deny.
The container is the boundary. The emulator has no Entra ID, so we prove the scope with a read-only SAS on finance. We run python scope_check.py.
from datetime import datetime, timedelta, timezone
from azure.core.exceptions import HttpResponseError
from azure.storage.blob import (BlobServiceClient,
ContainerSasPermissions, generate_container_sas)
from common import svc, show_err
sas = generate_container_sas( # finance only
svc.account_name, "finance",
account_key=svc.credential.account_key,
permission=ContainerSasPermissions(read=True, list=True),
expiry=datetime.now(timezone.utc) + timedelta(hours=8))
reader = BlobServiceClient(svc.url, credential=sas)
fin = reader.get_container_client("finance")
print("finance list:", list(fin.list_blob_names()))
gl = fin.download_blob("gl/2026/10/gl.csv").readall()
print("finance read:", gl.split(b"\n")[1])
try:
sales = reader.get_blob_client("sales", "2026/10/30/orders.csv")
sales.download_blob().readall()
except HttpResponseError as e:
print("sales read:"); show_err(e)
try:
fin.upload_blob("gl/2026/10/adjustment.csv", b"4000,-50.00\n")
except HttpResponseError as e:
print("finance write:"); show_err(e)$ python scope_check.py
finance list: ['gl/2026/10/gl.csv']
finance read: b'4000,1250.00'
sales read:
HttpResponseError 403 AuthorizationFailure
Server failed to authenticate the request. Make sure the
value of the Authorization header is formed correctly
including the signature.
finance write:
HttpResponseError 403 AuthorizationPermissionMismatch
This request is not authorized to perform this operation
using this permission.It lists ['gl/2026/10/gl.csv'] and reads b'4000,1250.00'. Reading sales fails with 403 AuthorizationFailure; on Azure it is AuthenticationFailed, because the SAS signature covers finance only. Writing to finance fails with 403 AuthorizationPermissionMismatch.
Stricter folders like payroll? A role on the finance container beats any ACL inside it, so payroll gets its own container, with its own group and role.
Finally, audit. Send the blob StorageRead, StorageWrite and StorageDelete logs to Log Analytics, and review who touched finance.
// Who touched finance this week? (blob logs)
StorageBlobLogs
| where TimeGenerated > ago(7d)
| where Uri has "/finance/"
| summarize requests = count() by RequesterUpn, OperationName
| order by requests descIf auditors want more than a container boundary, finance gets its own storage account.
Key points to remember
- Microsoft Entra ID first; the account key is a super-user: turn Shared Key off
- Managed identities + data roles (Reader / Contributor / Owner), scoped tight; up to 10 minutes to apply
- RBAC is checked first; ACLs add folder access and can't take a role away
- Partner SAS: one container, create + write, one day, HTTPS; prefer user delegation SAS
- Default ACLs shape new children only: apply changes recursively
The full script
Here is a Python script that writes every file and runs every command in order against Azurite; run pip install azure-storage-blob azure-storage-file-datalake pyarrow pandas first.
Show the full script that writes the files and runs every step
# ========================================================================
# ADLS Gen2 Interview Q&A #4 - Security and access control
# TechBrothersIT. Names and sample data are invented for teaching.
# Every step below was run on Azurite 3.37.0 (Microsoft's open-source Azure Storage emulator, Blob service)
# with azure-storage-blob 12.31.1, pyarrow and pandas; the outputs in the video and the blog post are the real outputs.
# To run it yourself:
# 1. npm install -g azurite then azurite-blob --skipApiVersionCheck --location ./azurite-data
# (or the Docker image mcr.microsoft.com/azure-storage/azurite), and leave it running on port 10000.
# --skipApiVersionCheck lets a newer azure-storage-blob talk to it.
# 2. pip install azure-storage-blob azure-storage-file-datalake pyarrow pandas requests
# 3. Set AZURE_STORAGE_CONNECTION_STRING to "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"
# then run python ADLS_Interview_QA_04_Code.py.
# Run it in an empty folder and on a freshly started emulator: it creates its files (and any local data
# files) there, and a second run on old data gives different output.
# Steps that restart the emulator say so in a comment: stop and start it by hand at that point.
# ========================================================================
import os, subprocess, time
def write(path, text):
if text is None:
if os.path.exists(path): os.remove(path)
return
os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
with open(path, "w", encoding="utf-8") as f:
f.write(text.strip("\n") + "\n")
def run(cmd, expect_error=False, allow_error=False, env=None):
print("\n$ " + cmd, flush=True)
rc = subprocess.run(cmd, shell=True, env=dict(os.environ, **(env or {}))).returncode
if rc != 0 and not (expect_error or allow_error):
raise SystemExit("stopped: this command was expected to succeed")
# Step 0: the starting files
write('common.py', 'import os\nimport textwrap\nfrom azure.storage.blob import BlobServiceClient\n\nsvc = BlobServiceClient.from_connection_string(\n os.environ["AZURE_STORAGE_CONNECTION_STRING"])\n\n\ndef container(name):\n """Get a container client, creating the container on first use."""\n c = svc.get_container_client(name)\n if not c.exists():\n c.create_container()\n return c\n\n\ndef show_err(e):\n code = getattr(e.error_code, "value", e.error_code)\n print(" ", type(e).__name__, e.status_code, code)\n first = str(e).split("\\n")[0] # first line, wrapped\n print(textwrap.fill(first, 62, initial_indent=" ",\n subsequent_indent=" "))\n')
# Step 1: The account key reads everything; an old key after rotation gets 403
write('keys.py', 'import os\nfrom azure.core.exceptions import HttpResponseError\nfrom azure.storage.blob import BlobServiceClient\nfrom common import svc, container, show_err\n\ncontainer("finance").upload_blob("gl/2026/10/gl.csv",\n b"account,amount\\n4000,1250.00\\n",\n overwrite=True)\ncontainer("sales").upload_blob("2026/10/30/orders.csv",\n b"order_id,amount\\n1001,25.50\\n",\n overwrite=True)\nprint("account key lists:", [c.name for c in svc.list_containers()])\ngl = svc.get_blob_client("finance", "gl/2026/10/gl.csv")\nrow = gl.download_blob().readall().split(b"\\n")[1]\nprint("account key reads:", row)\n\nconn = os.environ["AZURE_STORAGE_CONNECTION_STRING"]\nold = conn.replace(svc.credential.account_key, # rotated away\n "b2xkLWtleS1iZWZvcmUtcm90YXRpb24tMDAwMDAwMDA=")\napp = BlobServiceClient.from_connection_string(old)\ntry:\n list(app.list_containers())\nexcept HttpResponseError as e:\n print("old key after rotation:"); show_err(e)\n')
run('python keys.py')
# Step 2: A one-day partner SAS with create and write only: upload works, read and an expired SAS get 403
write('partner_sas.py', 'from datetime import datetime, timedelta, timezone\nfrom azure.core.exceptions import HttpResponseError\nfrom azure.storage.blob import (ContainerClient,\n ContainerSasPermissions, generate_container_sas)\nfrom common import svc, container, show_err\n\n\ndef partner_client(expiry):\n sas = generate_container_sas(\n svc.account_name, "partner-drop",\n account_key=svc.credential.account_key,\n permission=ContainerSasPermissions(create=True, write=True),\n expiry=expiry) # sp=cw: no read, no list\n return ContainerClient.from_container_url(\n f"{svc.url}partner-drop?{sas}")\n\n\ncontainer("partner-drop")\nnow = datetime.now(timezone.utc)\npartner = partner_client(now + timedelta(days=1)) # one day only\npartner.upload_blob("2026-10-30/stock.csv", b"sku,qty\\nA1,5\\n")\nprint("upload: ok")\ntry:\n partner.download_blob("2026-10-30/stock.csv").readall()\nexcept HttpResponseError as e:\n print("read back:"); show_err(e)\nexpired = partner_client(now - timedelta(minutes=5)) # the day after\ntry:\n expired.upload_blob("2026-10-31/stock.csv", b"sku,qty\\nA1,4\\n")\nexcept HttpResponseError as e:\n print("upload with an expired SAS:"); show_err(e)\n')
run('python partner_sas.py')
# Step 3: An account SAS sees every container; a user delegation key needs Microsoft Entra ID
write('account_sas.py', 'from datetime import datetime, timedelta, timezone\nfrom azure.core.exceptions import HttpResponseError\nfrom azure.storage.blob import (AccountSasPermissions,\n BlobServiceClient, ResourceTypes, generate_account_sas)\nfrom common import svc, show_err\n\nnow = datetime.now(timezone.utc)\nsas = generate_account_sas(\n svc.account_name, svc.credential.account_key,\n resource_types=ResourceTypes(service=True, container=True,\n object=True),\n permission=AccountSasPermissions(read=True, list=True),\n expiry=now + timedelta(hours=8))\nreader = BlobServiceClient(svc.url, credential=sas)\nprint("account SAS lists:",\n [c.name for c in reader.list_containers()])\ngl = reader.get_blob_client("finance", "gl/2026/10/gl.csv")\nrow = gl.download_blob().readall().split(b"\\n")[1]\nprint("account SAS reads:", row)\ntry:\n reader.create_container("scratch")\nexcept HttpResponseError as e:\n print("create container:"); show_err(e)\ntry: # needs a Microsoft Entra token\n svc.get_user_delegation_key(now, now + timedelta(hours=8))\nexcept HttpResponseError as e:\n print("user delegation key with the account key:"); show_err(e)\n')
run('python account_sas.py')
# Step 4: A read-only SAS scoped to the finance container: finance yes, sales no, no writes
write('scope_check.py', 'from datetime import datetime, timedelta, timezone\nfrom azure.core.exceptions import HttpResponseError\nfrom azure.storage.blob import (BlobServiceClient,\n ContainerSasPermissions, generate_container_sas)\nfrom common import svc, show_err\n\nsas = generate_container_sas( # finance only\n svc.account_name, "finance",\n account_key=svc.credential.account_key,\n permission=ContainerSasPermissions(read=True, list=True),\n expiry=datetime.now(timezone.utc) + timedelta(hours=8))\nreader = BlobServiceClient(svc.url, credential=sas)\nfin = reader.get_container_client("finance")\nprint("finance list:", list(fin.list_blob_names()))\ngl = fin.download_blob("gl/2026/10/gl.csv").readall()\nprint("finance read:", gl.split(b"\\n")[1])\ntry:\n sales = reader.get_blob_client("sales", "2026/10/30/orders.csv")\n sales.download_blob().readall()\nexcept HttpResponseError as e:\n print("sales read:"); show_err(e)\ntry:\n fin.upload_blob("gl/2026/10/adjustment.csv", b"4000,-50.00\\n")\nexcept HttpResponseError as e:\n print("finance write:"); show_err(e)\n')
run('python scope_check.py')
Part 5: Networking, Data Protection and Recovery
The sample data on this page is invented for teaching. Every terminal output is the real output of the command above it, run on Azurite 3.37.0, Microsoft's open-source Azure Storage emulator, with azure-storage-blob 12.31.1, pyarrow and pandas. Features the emulator does not support are shown as code. Part of the Real Time Azure Data Lake Storage Interview Questions and Answers series on TechBrothersIT. Features, limits and their status (GA or preview) are current as of October 2026; check the official Azure Storage documentation (learn.microsoft.com/azure/storage) for anything you quote in an interview.



No comments:
Post a Comment
Note: Only a member of this blog may post a comment.