SaveMyCert
Log in
5 of 5 free questions left today·for 10 a day
Secure, monitor, and troubleshoot Azure solutions

AI-200 Azure Key Vault and App Configuration: Secret Retrieval, Rotation and Dynamic Settings

17 min readAI-200 · Secure, monitor, and troubleshoot Azure solutionsUpdated

Securing an Azure solution's secrets and settings means keeping credentials in Azure Key Vault, where apps read them with their own Microsoft Entra identity and where they are rotated without downtime, and keeping application settings in Azure App Configuration, which apps load, filter and refresh at runtime. This lesson covers the two AI-200 skills in this area: securing secrets with Key Vault, including retrieval with the Python SDK, least-privilege RBAC roles, versions, event-driven and native rotation and soft delete; and storing and retrieving configuration with App Configuration, including selectors and labels, sentinel-based refresh, Key Vault references, snapshots and feature flags.

What you’ll learn
  • Retrieve secrets with SecretClient and DefaultAzureCredential, choosing latest versus pinned versions and caching values to avoid throttling.
  • Pick the least-privileged Key Vault and App Configuration roles, telling data-plane roles from control-plane look-alikes.
  • Manage secret versions and attributes: new values with set_secret, metadata and disabling with update_secret_properties, and why expiry is informational.
  • Implement secret rotation with SecretNearExpiry, Event Grid and a function, including the two-credential pattern that avoids downtime.
  • Choose native rotation policies for keys and lifetime actions for certificates over custom code, and know when Notify is needed instead.
  • Recover, purge and re-create soft-deleted secrets, and explain retention and purge protection limits.
  • Load App Configuration with selectors, labels, trim_prefixes, sentinel refresh, Key Vault references, snapshots and feature flags from Python.

Retrieving secrets with SecretClient and DefaultAzureCredential

An app retrieves a secret by creating one long-lived SecretClient for the vault URL with a Microsoft Entra credential such as DefaultAzureCredential, then calling get_secret(name). With no version argument the call returns the current (latest) version, so code that reads by name keeps working when someone stores a new version.

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

client = SecretClient(vault_url="https://kv-orders.vault.azure.net",
                      credential=DefaultAzureCredential())

latest = client.get_secret("db-password")          # current version
older = client.get_secret("db-password", version=vid)  # one exact version
print(latest.value, latest.properties.version)

The calls differ in what they return, and the difference matters whenever code needs values rather than metadata:

CallReturnsContains the value?
get_secret(name)KeyVaultSecret for the latest versionYes
get_secret(name, version=id)KeyVaultSecret for that version (audits, incident reviews)Yes
list_properties_of_secrets()SecretProperties for every secret: name, enabled, dates, tags, content typeNo
list_properties_of_secret_versions(name)SecretProperties for every version of one secretNo
get_deleted_secret(name)A soft-deleted secret's metadata, only after a deleteNo

Listings are for discovery: to export or use values, iterate the properties and call get_secret(props.name).value for each one. Pinning a version ID in configuration freezes the value, which suits an audit that must see exactly what a job used, but not an app that has to follow rotation.

Which identity DefaultAzureCredential uses

Locally DefaultAzureCredential uses your developer sign-in; in Container Apps, App Service or Functions it uses the resource's managed identity (on AKS, Microsoft Entra Workload ID federated with a managed identity). If the resource has several user-assigned identities and no client ID is given, the token request is ambiguous and fails. Pass DefaultAzureCredential(managed_identity_client_id="<client id>") (or set AZURE_CLIENT_ID) for the identity that holds the Key Vault role. Choosing a different identity, or enabling a system-assigned one, gets a token for a principal with no access.

Retrieval at scale: cache, back off, invalidate

Key Vault limits the transactions each vault accepts, and an API that calls get_secret on every request will receive HTTP 429 (Too Many Requests) under load. Microsoft's guidance is to:

  • Cache secrets in memory and reuse them, re-reading from Key Vault only when the cached copy stops working (for example after a rotation) or when you learn a new version exists.
  • Retry 429 responses with exponential backoff, never in a tight loop. The Azure SDK clients already retry with backoff by default.
  • Invalidate on events instead of polling: subscribe a handler to the SecretNewVersionCreated Event Grid event and evict the cached value when it fires.

Creating a new client per request or listing properties on every request keeps the call rate high and fixes nothing.

Key Vault access: Azure RBAC data-plane roles and least privilege

On a vault that uses the Azure RBAC permission model, reading or writing secrets, keys and certificates requires a Key Vault data-plane role; management roles such as Key Vault Contributor manage the vault resource but grant no access to its contents. Azure RBAC is Microsoft's recommended model (and the default for new vaults in current API versions). On an RBAC vault, access policies are ignored, so adding one never fixes a 403.

RolePlaneWhat it allows
Key Vault Secrets UserDataRead secret contents. Least privilege for an app that only reads secrets.
Key Vault Secrets OfficerDataEvery secret action: set new versions, update properties, delete, recover, purge. Nothing on keys or certificates. Fits a rotation function.
Key Vault Crypto OfficerDataEvery key action except managing permissions, including rotation policies and rotating on demand. Nothing on secrets or certificates.
Key Vault Crypto User / Crypto Service Encryption UserDataUse keys (encrypt, wrap, sign); the second is for services such as Storage using a customer-managed key. No key management.
Key Vault ReaderDataRead metadata of secrets, keys and certificates, never secret values.
Key Vault AdministratorDataAll data-plane operations on all object types. Works, but too broad for one job.
Key Vault Data Access AdministratorControl (authorization)Add or remove assignments of Key Vault data-plane roles only (constrained by a condition); has no data actions itself.
Key Vault ContributorControlManage the vault resource (networking, settings). No data access on an RBAC vault.

Two rules follow. A control-plane role such as Key Vault Contributor grants no data access, so reading a secret needs a data-plane role (Key Vault Secrets User for read-only); new assignments can take a few minutes to apply. And an identity whose only job is managing data-plane role assignments, with no data access of its own and no power to grant arbitrary roles, fits Key Vault Data Access Administrator, which can be constrained to Key Vault data roles. User Access Administrator can assign any role, and Key Vault Administrator can read data but cannot manage assignments.

Secret versions and attributes: set_secret versus update_secret_properties

Every Key Vault secret is a name with a history of versions: set_secret(name, value) always adds a new version that becomes current, while update_secret_properties changes metadata on an existing version without touching the value or creating a version.

NeedCallEffect
Replace the value (new password)set_secret(name, new_value)New version; versionless readers get it on their next read
Add or change tagsupdate_secret_properties(name, tags=...)No new version (even set_secret with the same value creates one)
Block one leaked versionupdate_secret_properties(name, version, enabled=False)That version can no longer be read; history and other versions stay
Set expiry or activation datesupdate_secret_properties(..., expires_on=..., not_before=...)Metadata only; see below

Attributes behave differently. enabled is enforced per version: a get on a disabled version fails. The expiration (exp) and not-before (nbf) dates are informational for secrets: Key Vault still returns an expired secret's value from a get, so an expiry date alone never stops anyone from using an old credential. To actually retire a credential, change it at its source (rotation) or disable the version. Expiry still matters, because it drives the near-expiry events that start rotation. Tags are free-form key-value pairs that scans and automation read; content_type is a single descriptive string about the value's format, not a place for ownership metadata.

Avoid creating a new name for a new value (such as orders-api-key-new): readers that use the old name never see it. And deleting a secret to re-create it fails while the deleted name is still held by soft delete.

Event-driven secret rotation with SecretNearExpiry and Event Grid

Key Vault cannot generate new values for secrets, so secret rotation is event-driven code: Key Vault publishes SecretNearExpiry to Event Grid 30 days before a secret version's expiration date, an Event Grid subscription triggers a function, and the function creates a new credential at the source, stores it as a new secret version with a fresh expiration date, and leaves apps to pick it up.

  1. Create the secret with an expiration date. A version with no exp never qualifies for SecretNearExpiry, so the function silently never runs, with no errors anywhere.
  2. Subscribe a function (Azure Functions, a webhook, or a queue the worker reads) to Microsoft.KeyVault.SecretNearExpiry on the vault.
  3. In the function, change the credential at the source first (the database login, the partner's REST API), then call set_secret with the new value and a new expires_on. Writing the vault last means the vault never holds a value the source does not accept.
  4. Give the function's identity Key Vault Secrets Officer on an RBAC vault; Secrets User can read but cannot write the new version.
def rotate(event):                       # Event Grid trigger
    name = event.get_json()["ObjectName"]
    new_pw = make_password()
    change_db_login_password(new_pw)     # 1. source first
    client.set_secret(name, new_pw,      # 2. then the vault
        expires_on=now() + timedelta(days=60))

The secret events are easy to confuse, so match each to its job:

EventFires whenTypical use
SecretNearExpiryThe current version is 30 days from its expiration dateStart a rotation
SecretExpiredThe expiration date has passedAlerting; too late to rotate without risk
SecretNewVersionCreatedA new version was writtenInvalidate caches, notify consumers; reports a rotation rather than starting one
VaultAccessPolicyChangedAn access policy changedPermission auditing, not secret lifecycle

Keys and certificates have matching events (KeyNearExpiry, CertificateNearExpiry and so on). Event delivery does not depend on diagnostic settings or Log Analytics, and the function's Key Vault role has nothing to do with whether Event Grid can deliver to it.

Two-credential rotation: alternating keys without downtime

For a resource that has two credentials, such as a storage account's key1 and key2, rotate without downtime by alternating: each new secret version holds the other key, and the function always regenerates the key that the latest version does not hold. Apps still using the previous version keep working for a whole rotation cycle while they pick up the new one.

Single-credential rotation (regenerate the key in use, then store it) breaks every app that has cached the old value until it re-reads the secret, so failures last up to one cache interval after each rotation. Regenerating both keys at once has the same problem, and shortening the re-read interval only narrows the outage.

Knowing which key is current

Microsoft's two-credential sample records the state in tags on each secret version: CredentialId (key1 or key2), ProviderAddress (the resource ID of the storage account) and ValidityPeriodDays. When SecretNearExpiry arrives, the function reads the latest version's CredentialId, regenerates the other key, and stores it as a new version with the tag switched. The event identifies the vault, object name, version and dates, but not which key a version holds.

Side effects of regenerating a key

An account-level SAS token is signed with one account key, and regenerating that key revokes the token immediately, whatever its expiry says. With alternation, a token signed with the key regenerated tonight stops working tonight, while one signed with the other key survives until the next rotation. Plan to reissue such tokens after each rotation, or move clients to Microsoft Entra authorization or user delegation SAS, which do not depend on account keys.

Native autorotation for keys and certificates

Unlike secrets, Key Vault keys rotate natively through a rotation policy, and certificates renew natively through lifetime actions in their certificate policy, so neither needs custom rotation code when Key Vault can create the new material itself.

ObjectNative mechanismCustom code needed?
SecretNone: SecretNearExpiry event plus your functionYes, always
Key (generated in Key Vault)Rotation policy with a Rotate lifetime actionNo
Key (imported material, such as from an on-premises HSM)Rotation policy with a Notify lifetime action (near-expiry event)Yes: the event triggers your own process to import new material
CertificateCertificate policy lifetime action (auto-renew or email contacts)No, for self-signed or integrated-CA certificates

Rotation policy details

  • A Rotate action fires at timeAfterCreate (for example P90D) or timeBeforeExpiry; the interval cannot be shorter than seven days. Key Vault creates the new version itself.
  • A Notify action publishes a near-expiry event and is timed only with timeBeforeExpiry (timeAfterCreate applies only to Rotate). Notification requires an expiryTime in the policy and an expiration date on the key.
  • expiryTime in the policy sets the expiration of each new version.
  • You can also rotate on demand (rotate_key in the Python KeyClient).
  • Managing rotation policies is key management: on an RBAC vault, Key Vault Crypto Officer is the least-privileged role, with no rights over secrets or certificates.

Services that use a versionless key URI, such as Azure Storage with a customer-managed key, pick up the new key version automatically. An expiration date on its own replaces nothing; it only marks the date.

When a vault holds a mix, choose per object: a rotation policy for a generated key (zero code) and an event-driven function for a password that only an external system can change. Writing functions for everything works but adds code nobody needed.

Soft delete, recovery and purge protection

Soft delete means a deleted secret, with every version, stays in a deleted state for the vault's retention period (7 to 90 days, 90 by default), during which its name stays reserved: you can recover it or purge it, but not create a new secret with that name. Soft delete is always on and cannot be disabled.

OperationSDK callResult
Deletebegin_delete_secret(name) (long-running; returns a poller)Secret moves to the deleted state; name reserved
Recoverbegin_recover_deleted_secret(name)Secret returns as it was, with all versions
Purgepurge_deleted_secret(name)Permanently removed; name free again
Restore a backuprestore_secret_backup(blob)Fails while a secret or deleted secret with that name exists

Common consequences:

  • Re-creating a deleted name fails with a conflict. To store a new value under the same name today, recover the deleted secret and call set_secret; the new value becomes its latest version.
  • Test pipelines that must leave nothing behind wait for the delete to finish, then purge. Purging before the delete operation completes fails.
  • The retention period is fixed when the vault is created and cannot be changed later. To keep deleted items for less time, purge them, or create a new vault with a shorter retention.
  • Purge protection blocks purging until the retention period ends, and once enabled it cannot be turned off. With it on, recovery is the only fast path back to a usable name.
  • On an RBAC vault, Key Vault Secrets Officer covers delete, recover and purge for secrets.
poller = client.begin_delete_secret("ci-temp-secret")
poller.wait()                       # deletion must complete first
client.purge_deleted_secret("ci-temp-secret")

Azure App Configuration: authentication, selectors and labels

Azure App Configuration is a managed store for application settings (key-values) and feature flags; a Python app reads it with the azure-appconfiguration-provider package, whose load() function returns a dictionary-like configuration built from the key-values its selectors match.

Microsoft Entra ID and data-plane roles

App Configuration accepts two kinds of authentication: access keys (connection strings) and Microsoft Entra ID. With Entra ID, call load(endpoint=..., credential=DefaultAzureCredential()) and give the identity a data-plane role:

RolePlaneWhat it allows
App Configuration Data ReaderDataRead key-values (least privilege for an app)
App Configuration Data OwnerDataRead, write and delete key-values and snapshots
App Configuration Reader / ReaderControlSee the store's properties; no key-values
App Configuration Contributor / Contributor / OwnerControlManage the store; can list access keys while they are enabled, but no data actions

When access-key authentication is disabled, Entra ID with a data role is the only path to the data, so even an Owner gets 403 when writing key-values until assigned Data Owner. Raising a control-plane role to a wider scope adds no data actions. To retire keys safely, first move every service to endpoint plus credential with Data Reader, then disable access-key authentication; doing it the other way round breaks the services. Read-only keys are still keys.

Selecting what to load

from azure.appconfiguration.provider import load, SettingSelector

config = load(
    endpoint=ep, credential=cred,
    selects=[
        SettingSelector(key_filter="*", label_filter="\0"),  # defaults
        SettingSelector(key_filter="*", label_filter="prod"),  # overrides
    ],
    trim_prefixes=["Checkout:"],
)
  • Default load: with no selects, load() reads all keys with no label only, so labelled values never arrive.
  • Key filters: Checkout:* matches every key that starts with Checkout:; Checkout: without the asterisk is an exact key name.
  • Labels create variants of the same key, typically per environment or version. \0 as a label filter means "no label".
  • Later selectors win: when two selectors return the same key, the value from the later selector is kept. Load unlabelled defaults first and the environment label second to get overrides with fallback; reversed, the defaults win. A single label_filter="*" mixes all labels with no defined winner.
  • trim_prefixes removes prefixes from the names the app sees (the store keeps Checkout:Endpoint; the app reads Endpoint). It changes names, not what is loaded.

Dynamic refresh with a sentinel key, and Key Vault references

Dynamic refresh lets a running app pick up changed settings without a restart: you tell load() which keys to watch (refresh_on) and how often a check is allowed (refresh_interval, 30 seconds by default), and the app calls config.refresh(), because the Python provider checks only when refresh() is called.

config = load(
    endpoint=ep, credential=cred,
    refresh_on=[WatchKey("Sentinel")],
    refresh_interval=30,
    on_refresh_success=rebuild_http_client,
)

@app.before_request
def check_config():
    config.refresh()  # no-op until the interval has elapsed
  • Call refresh() where activity happens, such as the start of each request. Before the interval has elapsed it returns immediately without contacting the store, so even thousands of requests a second cost one check per interval.
  • A failed refresh keeps the cached settings; the app runs on what it already loaded and tries again after the next interval. on_refresh_error can report the failure.
  • Sentinel pattern: watch one key and reload all selected settings when it changes. Operators change the real keys first and the sentinel last, so a reload sees a consistent set of related values. Watching every key multiplies requests and can reload half-way through an update.
  • Objects built from settings don't update themselves. The provider refreshes its own dictionary; an HTTP client built at startup keeps old values. Rebuild it in on_refresh_success, which runs only when a change was loaded.

Key Vault references

A Key Vault reference is a key-value whose value is a secret's URI, marked with a special content type, so a secret appears as a normal setting while staying in Key Vault. The provider resolves it from the app: pass keyvault_credential (or Key Vault clients, or a resolver) to load(), and the app's own identity calls Key Vault. That identity needs Key Vault Secrets User on the vault; the store's managed identity and store roles play no part, and App Configuration never calls Key Vault itself.

The provider caches resolved secrets. Sentinel refresh reloads only when a watched key in App Configuration changes, and a rotation that writes only to Key Vault changes nothing there (the reference URI stays the same). For versionless references, pass secret_refresh_interval so the provider re-reads resolved secrets periodically and picks up new versions. App Service's @Microsoft.KeyVault(...) app-setting references are a different, platform-side feature covered with App Service hosting.

Snapshots and feature flags in App Configuration

A snapshot is an immutable, named set of key-values captured from the filters given when it is created; an app that loads it by name always gets exactly that set, which makes releases deterministic and rollbacks a matter of naming an earlier snapshot. Labels, JSON values and sentinels group or signal changes, but the values they point to stay editable.

  • Load one with SettingSelector(snapshot_name="rel-42"). A snapshot selector cannot be combined with key or label filters.
  • Snapshots have a composition type. Key composition keeps one value per key: when a key matches several filters, the value from the last filter is included, so list unlabelled defaults first and the environment label last. Key-label composition keeps every label of a key, and the provider cannot load it. A snapshot cannot be edited, so a wrong composition means re-creating it.
  • To move between snapshots at runtime without code changes or restarts, select a snapshot reference: a key-value whose value names a snapshot. Current Python provider versions resolve it, and when refresh is configured and the reference changes, it unloads the old snapshot's values and loads the new one. Reading a name from an environment variable still needs a restart.

Feature flags

Feature flags are stored separately from ordinary key-values, and the provider loads them only when asked:

config = load(
    endpoint=ep, credential=cred,
    feature_flag_enabled=True,           # load flags
    feature_flag_selectors=[SettingSelector(key_filter="*",
                                            label_filter="prod")],
    feature_flag_refresh_enabled=True,   # pick up flag changes
)
fm = FeatureManager(config)              # featuremanagement package
if fm.is_enabled("NewCheckout"):
    ...
ArgumentWhat it does
feature_flag_enabled=TrueLoads flags (unlabelled ones by default) into the feature_management section
feature_flag_selectorsChooses which flags by key and label; the ordinary selects list does not affect flags
feature_flag_refresh_enabled=TrueMakes refresh() check all loaded flags for changes

Configuration refresh and flag refresh are independent: a sentinel change reloads settings but not flags, so a toggled flag stays stale until feature_flag_refresh_enabled is set. Flags are evaluated with FeatureManager(config).is_enabled(name), which also applies any feature filters, rather than by reading a key as a boolean.

Tip. Questions on this topic are short developer scenarios with one deciding requirement, such as least privilege, keeping old versions, no new version, no downtime, no custom code, no restart or nothing left behind. Several show Python SecretClient or azure-appconfiguration-provider code with a missing call or argument and ask which line completes it. Expect near-twin options: get_secret versus property listings, set_secret versus update_secret_properties, Secrets User versus Secrets Officer versus Key Vault Reader or Contributor, data-plane versus control-plane App Configuration roles, SecretNearExpiry versus SecretNewVersionCreated, rotation policies versus event-driven functions, Rotate versus Notify actions, recover versus purge, selector order, and settings refresh versus feature flag refresh. Troubleshooting items give a symptom (a 403, a conflict on create, a function that never runs, failures after each rotation, stale settings) and ask for the cause or fix. Some items are select-two.

Key takeaways
  • get_secret(name) returns the latest version; pass version= only to pin. Property listings never include values.
  • On an RBAC vault, Secrets User reads, Secrets Officer writes and rotates, Crypto Officer manages keys; Key Vault Contributor has no data access and access policies are ignored.
  • set_secret always creates a new version; update_secret_properties changes tags, enabled and dates without one. Disabled versions are blocked, expired ones are still readable.
  • Secrets rotate through code: SecretNearExpiry (30 days before exp, which must be set) triggers a function holding Secrets Officer that changes the source first, then the vault.
  • Two-credential rotation regenerates the key the latest version doesn't hold, tracked with a CredentialId tag; regenerating a key revokes SAS tokens it signed.
  • Keys rotate natively with a rotation policy (minimum 7 days); imported keys use a Notify action, which needs timeBeforeExpiry, a policy expiryTime and a key expiration date.
  • Soft delete reserves the name for 7 to 90 days fixed at vault creation; recover to reuse it, purge to free it, and purge protection can never be turned off.
  • App Configuration's load() reads unlabelled keys by default; later selectors win; refresh happens only when the app calls refresh(), and the sentinel is updated last.
  • Key Vault references are resolved by the app's own identity via keyvault_credential; secret_refresh_interval picks up rotated secrets.
  • Snapshots are immutable (only Key composition loads); feature flags need feature_flag_enabled, their own selectors and their own refresh switch.

Frequently asked questions

Does Azure Key Vault block a secret after its expiration date?

No. For secrets, the expiration and not-before dates are informational: Key Vault still returns the value of an expired secret from a get call. To stop a credential from being used, rotate it at its source or set enabled to False on that secret version, which Key Vault does enforce. The expiration date is still useful because it triggers the SecretNearExpiry event that starts automated rotation.

Which role does an app need to read secrets from an Azure Key Vault that uses Azure RBAC?

Key Vault Secrets User is the least-privileged built-in role that reads secret values. Key Vault Secrets Officer adds writing, deleting and purging secrets, which a rotation function needs. Key Vault Reader sees only metadata, Key Vault Contributor manages the vault resource without data access, and access policies have no effect on a vault that uses the RBAC permission model.

How do you rotate a secret automatically in Azure Key Vault?

Key Vault cannot generate secret values, so rotation is event-driven. Give the secret an expiration date, subscribe a function to the SecretNearExpiry event through Event Grid, and have the function create a new credential at its source and store it with set_secret as a new version with a new expiration date. The function's identity needs Key Vault Secrets Officer. For resources with two keys, alternate between them so apps never hold a revoked key.

What is the difference between rotating a key and rotating a secret in Key Vault?

Keys support a native rotation policy: a Rotate lifetime action makes Key Vault create a new key version at a set time after creation or before expiry, with no code. Secrets have no native rotation, so they need a SecretNearExpiry event and a function. Certificates renew through lifetime actions in their certificate policy. Keys imported from an HSM can only use a Notify action, which raises a near-expiry event for your own import process.

Why can't I create a Key Vault secret with the name of one I just deleted?

Soft delete keeps a deleted secret, with all its versions, for the vault's retention period, and the name stays reserved during that time, so creating it again returns a conflict. Recover it with begin_recover_deleted_secret and set a new value, or wait for the delete operation to finish and purge it with purge_deleted_secret. If purge protection is enabled, purging is blocked until retention ends, so recovery is the only fast option.

Why doesn't my Python app pick up changes from Azure App Configuration?

The Python configuration provider checks for changes only when the app calls refresh() on the loaded configuration, and only after the refresh interval (30 seconds by default) has passed. The app also needs refresh_on with a watched key, usually a sentinel key that operators update after all other changes. Feature flags refresh separately and need feature_flag_refresh_enabled, and secrets from Key Vault references need secret_refresh_interval.

How do labels work when loading App Configuration settings in Python?

Labels create variants of the same key, such as per environment. Calling load() with no selects reads only key-values with no label. To use environment overrides with fallback, pass one SettingSelector for the empty label (\0) followed by one for the environment label; when two selectors return the same key, the later selector's value wins.

Who resolves a Key Vault reference stored in Azure App Configuration?

The application does. The reference is only a key-value holding the secret's URI; the configuration provider sees it and calls Key Vault with the credential passed as keyvault_credential. The app's identity therefore needs Key Vault Secrets User on the vault, while the App Configuration store's own identity is not involved.

Source

This lesson covers the "Secure, monitor, and troubleshoot Azure solutions" domain of the official AI-200 exam guide. Vendors revise their guides — check the source for the current version.

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.

Spotted a mistake in this lesson?