Repository navigation
[Microsoft.Web] Introduce api version 2026-09-01 and VirtualConnections Entity #45406
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
20e4ab2
a5c7e8a
009752b
92c31dc
5873ec9
97da8fa
2a8a4bc
4cfb77a
0ac74a1
272529b
605fe07
886dc25
97661f9
e0c26b7
2eb33c4
5ca6f72
575b4f3
04309c3
19ab9cb
9902043
264b873
ffb6b06
7e18e1c
597de62
ee32e63
5b7a2b9
b328fb8
2d525e7
3dc3a39
8fca085
461a603
d0c41a7
c0125ef
7e482a4
a985531
fed7ff8
a2646b4
c518744
89fef84
166f5f7
6749315
1f46498
10c2fa7
4a4afd4
33eea96
32bbf6a
9fb22e2
c626632
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,372 @@ | ||
| import "@azure-tools/typespec-azure-core"; | ||
| import "@azure-tools/typespec-azure-resource-manager"; | ||
| import "@typespec/rest"; | ||
| import "@typespec/versioning"; | ||
| import "./models.tsp"; | ||
| import "./Site.tsp"; | ||
|
|
||
| using TypeSpec.Rest; | ||
| using Azure.ResourceManager; | ||
| using TypeSpec.Http; | ||
| using TypeSpec.Versioning; | ||
|
|
||
| namespace Microsoft.Web; | ||
|
|
||
| /** | ||
| * Egress configuration for a web app. Declares which app settings | ||
| * and connection strings are virtualized so secrets never enter the application | ||
| * sandbox at runtime. | ||
| * | ||
| * This is a proxy-only configuration singleton following the established pattern | ||
| * of other config sub-resources (authsettingsV2, azurestorageaccounts). | ||
| */ | ||
| @added(Versions.v2026_09_01) | ||
| @singleton("egress") | ||
| @parentResource(Site) | ||
| model EgressConfig | ||
| is Azure.ResourceManager.ProxyResource<EgressConfigProperties> { | ||
| ...ResourceNameParameter< | ||
| Resource = EgressConfig, | ||
| KeyName = "config", | ||
| SegmentName = "config", | ||
| NamePattern = "" | ||
| >; | ||
| } | ||
|
|
||
| /** Properties of the egress configuration. */ | ||
| #suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-provisioning-state" "egress is a proxy-only sites/config singleton that is written synchronously and does not track a provisioning state, consistent with the other Microsoft.Web config singletons such as authsettingsV2." | ||
|
Check warning on line 37 in specification/web/resource-manager/Microsoft.Web/AppService/EgressConfig.tsp
|
||
| @added(Versions.v2026_09_01) | ||
| model EgressConfigProperties { | ||
| /** Whether virtual connections are enabled for this site. */ | ||
| enabled?: EgressEnabledState; | ||
|
|
||
| /** | ||
| * All virtualized connections. Key is a customer-chosen connection name | ||
| * (e.g., "sql", "cache", "storage") of at most 256 characters, which must not | ||
| * end in whitespace and must be unique within the site regardless of casing. | ||
| * | ||
| * This collection is authoritative: a write replaces the stored connections in | ||
| * full, and omitting it (or supplying an empty object) deletes the egress | ||
| * configuration for the site. | ||
| */ | ||
| #suppress "@azure-tools/typespec-azure-resource-manager/arm-no-record" "Connection names are arbitrary customer-chosen keys and cannot be represented as a fixed set of model properties." | ||
|
Check warning on line 52 in specification/web/resource-manager/Microsoft.Web/AppService/EgressConfig.tsp
|
||
| connections?: Record<VirtualConnection>; | ||
| } | ||
|
|
||
| /** Enabled state for virtual connections. */ | ||
| #suppress "@azure-tools/typespec-azure-core/no-closed-literal-union" "The 2026-09-01 service rejects unknown egress enabled states, so this union intentionally models a closed set." | ||
|
Check warning on line 57 in specification/web/resource-manager/Microsoft.Web/AppService/EgressConfig.tsp
|
||
| @added(Versions.v2026_09_01) | ||
| union EgressEnabledState { | ||
| /** Virtual connections are enabled — proxy intercepts configured settings. */ | ||
| Enabled: "Enabled", | ||
|
|
||
| /** Virtual connections are disabled — all settings pass through unchanged. */ | ||
| Disabled: "Disabled", | ||
| } | ||
|
|
||
| /** | ||
| * Declares one backend connection to virtualize. Maps one or more app settings | ||
| * (or connection strings) to a proxy configuration with a specific protocol | ||
| * and authentication strategy. | ||
| */ | ||
| @added(Versions.v2026_09_01) | ||
| model VirtualConnection { | ||
| /** | ||
| * Settings that compose this connection. Key is the app setting | ||
| * (or connection string) name; value describes its role in the connection. | ||
| * Setting keys must be nonempty, must not end in whitespace, and must be | ||
| * unique within the connection regardless of casing. | ||
| * | ||
| * All referenced setting names must already exist in the selected source | ||
| * when the egress configuration is written. Missing app settings, missing | ||
| * connection strings, or ambiguous connection-string references cause | ||
| * create/update validation to fail. | ||
| */ | ||
| #suppress "@azure-tools/typespec-azure-resource-manager/arm-no-record" "Setting names are arbitrary customer-chosen keys and cannot be represented as a fixed set of model properties." | ||
|
Check warning on line 85 in specification/web/resource-manager/Microsoft.Web/AppService/EgressConfig.tsp
|
||
| settings: Record<VirtualConnectionSetting>; | ||
|
|
||
| /** | ||
| * Where to look up the settings. Default: "AppSettings". Each connection pulls | ||
| * from exactly one source — create separate connections if you need settings | ||
| * from both sources. | ||
| */ | ||
| source?: VirtualConnectionSettingSource = VirtualConnectionSettingSource.AppSettings; | ||
|
|
||
| /** Protocol for the backend service. */ | ||
| protocol: VirtualConnectionProtocol; | ||
|
|
||
| /** | ||
| * Authentication strategy for the backend connection. | ||
| * "Credential" — proxy injects the original secret (from setting value). | ||
| * "ManagedIdentity" — proxy acquires a managed identity token for upstream auth. | ||
| */ | ||
| auth: VirtualConnectionAuthType; | ||
|
|
||
| /** | ||
| * Managed Identity scope for token acquisition. Only relevant when auth=ManagedIdentity. | ||
| * Optional — the platform infers a default scope from protocol + host. | ||
| * Specify explicitly for custom hosts or non-standard resource URIs. | ||
| */ | ||
| identityScope?: string; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [NEW] 🟠 Warning [Section 12 — Types and Formats] Classification reasoning: Suggested fix: Change the TypeSpec property to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're keeping Microsoft Entra also supports application-ID-based scope strings—for example, Redis's documented
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Scope-inference validation is intentionally deferred until Control Plane and Secretless Proxy share the protocol/target inference behavior. |
||
|
|
||
| /** | ||
| * Per-connection override for the user-assigned managed identity resource ID. | ||
| * Used when multiple connections target different backends that require | ||
| * different identities. | ||
| * | ||
| * Only relevant when auth=ManagedIdentity. If omitted, create/update uses | ||
| * the app's system-assigned identity and rejects the request if that identity | ||
| * does not exist. If supplied, the referenced identity must already be | ||
| * assigned to the app; otherwise create/update validation fails. | ||
| */ | ||
| identityResourceId?: Azure.Core.armResourceIdentifier<[ | ||
| { | ||
| type: "Microsoft.ManagedIdentity/userAssignedIdentities"; | ||
| } | ||
| ]>; | ||
|
|
||
| /** | ||
| * How to inject a standalone credential into upstream HTTP requests. | ||
| * Required when protocol=Http + auth=Credential and the credential is a | ||
| * separate setting. Not needed for role="Value" or auth=ManagedIdentity. | ||
| */ | ||
| credentialInjection?: VirtualConnectionCredentialInjection; | ||
| } | ||
|
|
||
| /** | ||
| * Describes how the proxy injects a standalone credential setting into upstream | ||
| * HTTP requests. Only applies when protocol=Http and the credential is a | ||
| * separate setting (not embedded in a value/URL). | ||
| */ | ||
| @added(Versions.v2026_09_01) | ||
| model VirtualConnectionCredentialInjection { | ||
| /** HTTP header name to inject the credential into (e.g., "Authorization", "X-API-Key"). */ | ||
| header: string; | ||
|
|
||
| /** | ||
| * Format string for the header value. Use {value} as placeholder for the | ||
| * credential. Default: raw credential value (no formatting). | ||
| * Examples: "Bearer {value}", "Basic {value}", "ApiKey {value}". | ||
| */ | ||
| format?: string; | ||
| } | ||
|
|
||
| /** | ||
| * Describes the role of a single app setting or connection string within a | ||
| * virtual connection. | ||
| */ | ||
| @added(Versions.v2026_09_01) | ||
| model VirtualConnectionSetting { | ||
| /** | ||
| * The role this setting plays in the connection. The platform uses this to | ||
| * determine runtime behavior: | ||
| * - "Credential" settings are masked (app never sees the real value). | ||
| * - "Host"/"Value" settings identify the intercept target. | ||
| * - "Username" settings feed protocol auth construction. | ||
| */ | ||
| role: VirtualConnectionSettingRole; | ||
| } | ||
|
|
||
| /** Where to resolve settings from. */ | ||
| @added(Versions.v2026_09_01) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this enumeration will never add new values in a new api-version, please assert that in the justification. If it might add new values in new api-versions in the future, then it should be an open literal union (meaning you should add string as one of the variants. |
||
| union VirtualConnectionSettingSource { | ||
|
cmriachi marked this conversation as resolved.
|
||
| string, | ||
|
|
||
| /** App Settings (config/appsettings). */ | ||
| AppSettings: "AppSettings", | ||
|
|
||
| /** Connection Strings (config/connectionstrings). */ | ||
| ConnectionStrings: "ConnectionStrings", | ||
| } | ||
|
|
||
| /** Protocol for the backend service. */ | ||
| @added(Versions.v2026_09_01) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this enumeration will never add new values in a new api-version, please assert that in the justification. If it might add new values in new api-versions in the future, then it should be an open literal union (meaning you should add string as one of the variants. |
||
| union VirtualConnectionProtocol { | ||
| string, | ||
|
|
||
| /** HTTP/HTTPS (Azure Storage, Cosmos DB REST, Key Vault, custom APIs). */ | ||
| Http: "Http", | ||
|
|
||
| /** TDS (Azure SQL, SQL Server). */ | ||
| Tds: "Tds", | ||
|
|
||
| /** RESP (Azure Cache for Redis). */ | ||
| Redis: "Redis", | ||
|
|
||
| /** PostgreSQL wire protocol (Azure Database for PostgreSQL). */ | ||
| Postgres: "Postgres", | ||
| } | ||
|
|
||
| /** Authentication strategy for upstream connections. */ | ||
| @added(Versions.v2026_09_01) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this enumeration will never add new values in a new api-version, please assert that in the justification. If it might add new values in new api-versions in the future, then it should be an open literal union (meaning you should add string as one of the variants. |
||
| union VirtualConnectionAuthType { | ||
| string, | ||
|
|
||
| /** Proxy injects the original credential from the setting value. */ | ||
| Credential: "Credential", | ||
|
|
||
| /** Proxy acquires a Managed Identity token for upstream auth. */ | ||
| ManagedIdentity: "ManagedIdentity", | ||
| } | ||
|
|
||
| /** The role a setting plays in a connection. */ | ||
| @added(Versions.v2026_09_01) | ||
| union VirtualConnectionSettingRole { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this enumeration will never add new values in a new api-version, please assert that in the justification. If it might add new values in new api-versions in the future, then it should be an open literal union (meaning you should add string as one of the variants. |
||
| string, | ||
|
|
||
| /** Plain hostname or IP — identifies the intercept target. */ | ||
| Host: "Host", | ||
|
|
||
| /** Standalone secret (password, key, SAS token) — masked from app, used or replaced by proxy. */ | ||
| Credential: "Credential", | ||
|
|
||
| /** Standalone username — used for protocol auth construction (e.g., Redis ACL OID). */ | ||
| Username: "Username", | ||
|
|
||
| /** Composite value (connection string, SAS URL, DSN, Redis URI) — proxy parses based on protocol. */ | ||
| Value: "Value", | ||
| } | ||
|
|
||
| // ───────────────────────────────────────────────────────────────────────────── | ||
| // Operations — production slot: .../sites/{name}/config/egress | ||
| // ───────────────────────────────────────────────────────────────────────────── | ||
|
|
||
| @added(Versions.v2026_09_01) | ||
| @armResourceOperations | ||
| interface EgressConfigOps | ||
| extends Azure.ResourceManager.Legacy.LegacyOperations< | ||
| { | ||
| ...ApiVersionParameter, | ||
| ...SubscriptionIdParameter, | ||
| ...ResourceGroupParameter, | ||
| ...Azure.ResourceManager.Legacy.Provider, | ||
|
|
||
| /** Name of the app. */ | ||
| @path | ||
| @segment("sites") | ||
| @key | ||
| name: string, | ||
| }, | ||
| { | ||
| /** Name of the configuration singleton. */ | ||
| @path | ||
| @segment("config") | ||
| @key | ||
| egress: "egress", | ||
| }, | ||
| ResourceName = "EgressConfig" | ||
| > {} | ||
|
|
||
| @added(Versions.v2026_09_01) | ||
| @tag("WebApps") | ||
| @armResourceOperations(#{ omitTags: true }) | ||
| interface EgressConfigs { | ||
| /** | ||
| * Creates or replaces the egress configuration for an app. The supplied | ||
| * connections replace the stored ones in full, so connections omitted from | ||
| * the request are deleted; omitting connections entirely, or supplying an | ||
| * empty object, deletes the configuration for the app. Returns 201 when no | ||
| * configuration was stored for the app beforehand and 200 otherwise, with the | ||
| * stored configuration in the response body. | ||
| * | ||
| * The request is normalized and then structurally and semantically validated | ||
| * before persistence. Invalid configurations are rejected, including requests | ||
| * whose referenced setting names appear to contain credentials, which return | ||
| * 400 Bad Request. | ||
| */ | ||
| @summary("Creates or replaces the egress configuration for an app.") | ||
| createOrUpdateEgressConfig is EgressConfigOps.CreateOrUpdateSync< | ||
| EgressConfig, | ||
| Response = | ||
| | ArmResourceUpdatedResponse<EgressConfig> | ||
| | (CreatedResponse & { | ||
| @bodyRoot body: EgressConfig; | ||
| }), | ||
| OverrideErrorType = DefaultErrorResponse | ||
| >; | ||
|
|
||
| /** | ||
| * Gets the egress configuration stored for an app, including its connections. | ||
| * Returns an empty configuration when none is stored. | ||
| */ | ||
| @summary("Gets the stored egress configuration for an app.") | ||
| getEgressConfig is EgressConfigOps.Read< | ||
| EgressConfig, | ||
| OverrideErrorType = DefaultErrorResponse | ||
| >; | ||
| } | ||
|
|
||
| // ───────────────────────────────────────────────────────────────────────────── | ||
| // Operations — deployment slot: .../sites/{name}/slots/{slot}/config/egress | ||
| // ───────────────────────────────────────────────────────────────────────────── | ||
|
|
||
| @added(Versions.v2026_09_01) | ||
| @armResourceOperations | ||
| interface EgressConfigSlotOps | ||
| extends Azure.ResourceManager.Legacy.LegacyOperations< | ||
| { | ||
| ...ApiVersionParameter, | ||
| ...SubscriptionIdParameter, | ||
| ...ResourceGroupParameter, | ||
| ...Azure.ResourceManager.Legacy.Provider, | ||
|
|
||
| /** Name of the app. */ | ||
| @path | ||
| @segment("sites") | ||
| @key | ||
| name: string, | ||
|
|
||
| /** Name of the deployment slot. */ | ||
| @path | ||
| @segment("slots") | ||
| @key | ||
| slot: string, | ||
| }, | ||
| { | ||
| /** Name of the configuration singleton. */ | ||
| @path | ||
| @segment("config") | ||
| @key | ||
| egress: "egress", | ||
| }, | ||
| ResourceName = "EgressConfigSlot" | ||
| > {} | ||
|
|
||
| @added(Versions.v2026_09_01) | ||
| @tag("WebApps") | ||
| @armResourceOperations(#{ omitTags: true }) | ||
| interface EgressConfigSlotConfigs { | ||
| /** | ||
| * Creates or replaces the egress configuration for a deployment slot. The | ||
| * supplied connections replace the stored ones in full, so connections | ||
| * omitted from the request are deleted; omitting connections entirely, or | ||
| * supplying an empty object, deletes the configuration for the slot. Returns | ||
| * 201 when no configuration was stored for the slot beforehand and 200 | ||
| * otherwise, with the stored configuration in the response body. | ||
| * | ||
| * The request is normalized and then structurally and semantically validated | ||
| * before persistence. Invalid configurations are rejected, including requests | ||
| * whose referenced setting names appear to contain credentials, which return | ||
| * 400 Bad Request. | ||
| */ | ||
| @summary("Creates or replaces the egress configuration for a deployment slot.") | ||
| createOrUpdateEgressConfigSlot is EgressConfigSlotOps.CreateOrUpdateSync< | ||
| EgressConfig, | ||
| Response = | ||
| | ArmResourceUpdatedResponse<EgressConfig> | ||
| | (CreatedResponse & { | ||
| @bodyRoot body: EgressConfig; | ||
| }), | ||
| OverrideErrorType = DefaultErrorResponse | ||
| >; | ||
|
|
||
| /** | ||
| * Gets the egress configuration stored for a deployment slot, including its | ||
| * connections. Returns an empty configuration when none is stored. | ||
| */ | ||
| @summary("Gets the stored egress configuration for a deployment slot.") | ||
| getEgressConfigSlot is EgressConfigSlotOps.Read< | ||
| EgressConfig, | ||
| OverrideErrorType = DefaultErrorResponse | ||
| >; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.