|
78 | 78 |
|
79 | 79 | <!-- Path-based routing to appropriate backend service --> |
80 | 80 | <choose> |
81 | | -%{ if key_rotation_enabled ~} |
| 81 | +%{ if apim_keys_endpoint_enabled ~} |
82 | 82 | <!-- Internal endpoint: fetch APIM subscription keys from Key Vault --> |
83 | 83 | <!-- Returns both primary and secondary keys + rotation metadata as JSON --> |
| 84 | + <!-- Available for ALL subscription-key tenants (keys stored in KV for all) --> |
84 | 85 | <when condition="@(context.Request.Url.Path.ToLower().EndsWith("internal/apim-keys"))"> |
85 | 86 | <!-- Only allow GET --> |
86 | 87 | <choose> |
|
112 | 113 | <value>@("Bearer " + (string)context.Variables["kv-token"])</value> |
113 | 114 | </set-header> |
114 | 115 | </send-request> |
115 | | - <!-- Fetch rotation metadata from hub Key Vault --> |
| 116 | +%{ if key_rotation_enabled ~} |
| 117 | + <!-- Fetch rotation metadata from hub Key Vault (only for rotation-opted tenants) --> |
116 | 118 | <send-request mode="new" response-variable-name="kvMetadataResp" timeout="10" ignore-error="true"> |
117 | 119 | <set-url>@($"${keyvault_uri}secrets/${tenant_name}-apim-rotation-metadata?api-version=7.4")</set-url> |
118 | 120 | <set-method>GET</set-method> |
119 | 121 | <set-header name="Authorization" exists-action="override"> |
120 | 122 | <value>@("Bearer " + (string)context.Variables["kv-token"])</value> |
121 | 123 | </set-header> |
122 | 124 | </send-request> |
123 | | - <!-- Return explicit error if any Key Vault call failed --> |
| 125 | +%{ endif ~} |
| 126 | + <!-- Return explicit error if primary or secondary Key Vault reads failed --> |
124 | 127 | <choose> |
125 | 128 | <when condition="@( |
126 | 129 | ((IResponse)context.Variables["kvPrimaryResp"]) == null || ((IResponse)context.Variables["kvPrimaryResp"]).StatusCode >= 400 || |
127 | | - ((IResponse)context.Variables["kvSecondaryResp"]) == null || ((IResponse)context.Variables["kvSecondaryResp"]).StatusCode >= 400 || |
128 | | - ((IResponse)context.Variables["kvMetadataResp"]) == null || ((IResponse)context.Variables["kvMetadataResp"]).StatusCode >= 400 |
| 130 | + ((IResponse)context.Variables["kvSecondaryResp"]) == null || ((IResponse)context.Variables["kvSecondaryResp"]).StatusCode >= 400 |
129 | 131 | )"> |
130 | 132 | <return-response> |
131 | 133 | <set-status code="502" reason="Bad Gateway" /> |
|
135 | 137 | <set-body>@{ |
136 | 138 | var primaryResp = ((IResponse)context.Variables["kvPrimaryResp"]); |
137 | 139 | var secondaryResp = ((IResponse)context.Variables["kvSecondaryResp"]); |
138 | | - var metadataResp = ((IResponse)context.Variables["kvMetadataResp"]); |
139 | 140 |
|
140 | 141 | var result = new JObject( |
141 | 142 | new JProperty("error", new JObject( |
142 | 143 | new JProperty("code", "KeyVaultReadFailed"), |
143 | | - new JProperty("message", "Failed to read one or more APIM key secrets from Key Vault."), |
| 144 | + new JProperty("message", "Failed to read APIM key secrets from Key Vault."), |
144 | 145 | new JProperty("details", new JObject( |
145 | 146 | new JProperty("primary_status", primaryResp == null ? 0 : primaryResp.StatusCode), |
146 | | - new JProperty("secondary_status", secondaryResp == null ? 0 : secondaryResp.StatusCode), |
147 | | - new JProperty("metadata_status", metadataResp == null ? 0 : metadataResp.StatusCode) |
| 147 | + new JProperty("secondary_status", secondaryResp == null ? 0 : secondaryResp.StatusCode) |
148 | 148 | )) |
149 | 149 | )) |
150 | 150 | ); |
|
162 | 162 | <set-body>@{ |
163 | 163 | var primaryBody = ((IResponse)context.Variables["kvPrimaryResp"])?.Body?.As<JObject>(preserveContent: true); |
164 | 164 | var secondaryBody = ((IResponse)context.Variables["kvSecondaryResp"])?.Body?.As<JObject>(preserveContent: true); |
165 | | - var metadataBody = ((IResponse)context.Variables["kvMetadataResp"])?.Body?.As<JObject>(preserveContent: true); |
166 | 165 |
|
167 | 166 | var primaryKey = primaryBody?["value"]?.ToString() ?? ""; |
168 | 167 | var secondaryKey = secondaryBody?["value"]?.ToString() ?? ""; |
169 | | - var metadataRaw = metadataBody?["value"]?.ToString() ?? "{}"; |
170 | 168 |
|
| 169 | +%{ if key_rotation_enabled ~} |
| 170 | + var metadataBody = ((IResponse)context.Variables["kvMetadataResp"])?.Body?.As<JObject>(preserveContent: true); |
| 171 | + var metadataRaw = metadataBody?["value"]?.ToString() ?? "{}"; |
171 | 172 | JObject metadata; |
172 | 173 | try { metadata = JObject.Parse(metadataRaw); } |
173 | 174 | catch { metadata = new JObject(); } |
| 175 | +%{ else ~} |
| 176 | + var metadata = new JObject( |
| 177 | + new JProperty("key_rotation_enabled", false), |
| 178 | + new JProperty("message", "Automatic key rotation is not enabled for this tenant") |
| 179 | + ); |
| 180 | +%{ endif ~} |
174 | 181 |
|
175 | 182 | var result = new JObject( |
176 | 183 | new JProperty("tenant", "${tenant_name}"), |
|
0 commit comments