Azure SQL Database REST API v2014‑04‑01の使用検出と移行ガイド|Resource Graph・Activityログで網羅特定する実践手順

退役済みの Azure SQL Database REST API v2014‑04‑01 をどこで使っているのか――退職者が残した IaC やスクリプト、ジョブが相手でも、体系立てて洗えば十分に特定できます。本記事は “静的資産(テンプレート・コード)” と “実行時ログ(ARM/Activity)” の両輪で漏れなく見つけ、ゼロダウンタイムで新 API に移行する実践手順をまとめた決定版です。

目次

Azure SQL Database REST API v2014‑04‑01 の利用状況を特定する方法

想定シナリオ

2025 年 10 月 31 日に廃止予定(現在は廃止済み)の Microsoft.Sql の SQL Database REST API v2014‑04‑01 を、自社環境のどこが呼び出しているか不明。実装者は退職済みで引き継ぎ資料なし。安全に移行できるよう、利用箇所の網羅的な調査手順と、ヒット時の対応を知りたい。

全体像(最短ルート)

以下の順序で進めると、構成テンプレート・パイプライン・アプリコード・過去のデプロイ履歴・実行時の REST 呼び出しログまで横断的に洗い出せます。各ステップの結果が 0 件なら、そのスコープでは未使用と判断できます(監視のセクションで「今後も使われないこと」を継続検証)。

ステップ対象目的やること(要約)期待成果備考/落とし穴
1リソース プロバイダー登録調査前の前提確認サブスクリプションの Microsoft.Sql が登録済みかを Azure ポータル (サブスクリプション → リソース プロバイダー) で確認。未登録なら登録。後続クエリの正常化未登録だと一部クエリや操作結果が空になることがある
2Azure Resource Graph(ARG)過去のデプロイ テンプレート横断検索microsoft.resources/deployments の properties.template を全文検索/展開して、"apiVersion": "2014-04-01" を検出ARM/Bicep による登録履歴の発見テンプレートリンク(外部 URI)の場合は本文が保持されないことがある
3リソース グループのデプロイ履歴RG 単位の詳細追跡ポータルの リソース グループ → デプロイ でテンプレート JSON を検索。CLI で一括抽出も可どの RG に埋もれているか特定履歴保持の既定は最新 800 件まで
4Template Specs / Policy / Blueprint“配布用テンプレート” の一掃Template Spec の各バージョンと、DeployIfNotExists など Policy 内 ARM テンプレートを検索展開元となる「種」を根絶Blueprint は非推奨化の流れ。ある場合は重点確認
5コードリポジトリ/CIIaC と手書き REST の発見GitHub/Azure DevOps で api-version=2014-04-01 と "apiVersion": "2014-04-01" を全リポジトリ検索退職者のスクリプトも検知圧縮・生成物ディレクトリを除外して高速化
6実行時ログ(Activity/ARM)稼働中の呼び出し検出Log Analytics の AzureActivity で properties から api-version=2014-04-01 を全文検索今まさに使っている呼び出し元の特定Activity 既定保持は 90 日。長期は送信先の保持期間次第
7監視とガードレール再発防止・未検知対策アラート(Activity Log)、PR ゲート、CI ジョブで旧 API 使用をブロック/通知運用に回すゼロ件が続くことを観測で保証

ARG(Azure Resource Graph)で「テンプレート由来の使用痕跡」を一気に洗い出す

v2014‑04‑01 は管理プレーン(ARM)の API バージョンです。最優先で、過去の ARM/Bicep デプロイや Template Spec からの利用を確認します。ポイントは「deployments リソースの properties.template を検索」に絞ることです(resources テーブル直下のリソースは apiVersion を保持しません)。

① 過去のデプロイ(RG/サブスクリプション/管理グループ配下)を横断検索

Azure ポータルの「Resource Graph Explorer」または Azure CLI(az graph query)で次のクエリを実行します。

// デプロイ リソースに含まれるテンプレート本文を文字列検索
resources
| where type =~ 'microsoft.resources/deployments'
| extend tmpl = tostring(properties.template)
| where isnotempty(tmpl) and tmpl contains '"apiVersion": "2014-04-01"'
| project subscriptionId, resourceGroup, deploymentName=name, timeCreated=properties.timestamp, correlationId
| order by timeCreated desc

より厳密に、テンプレート配列を展開して「どの型のリソースで古い API を使っているか」を突き止めるには以下が有効です。

// テンプレート配列を展開し、apiVersion を列として抽出
resources
| where type =~ 'microsoft.resources/deployments'
| extend tmpl = parse_json(tostring(properties.template))
| mv-expand r1 = tostring(tmpl.resources)
| extend r1json = parse_json(r1)
| extend rType = tostring(r1json.type),
         rName = tostring(r1json.name),
         rApi  = tostring(r1json.apiVersion)
| where rApi == '2014-04-01'
| project subscriptionId, resourceGroup, deploymentName=name, rType, rName, rApi, timeCreated=properties.timestamp
| order by timeCreated desc

ネストした子リソース(resources[].resources[])まで確認したい場合は、再度 mv-expand します。

// 子リソースも調べる
resources
| where type =~ 'microsoft.resources/deployments'
| extend tmpl = parse_json(tostring(properties.template))
| mv-expand r1 = tostring(tmpl.resources)
| extend j1 = parse_json(r1)
| project subscriptionId, resourceGroup, deploymentName=name, timeCreated=properties.timestamp, j1
| mv-expand r2 = tostring(j1.resources) to typeof(string) limit 100000
| extend j2 = parse_json(r2)
| extend rType = coalesce(tostring(j2.type), tostring(j1.type)),
         rName = coalesce(tostring(j2.name), tostring(j1.name)),
         rApi  = coalesce(tostring(j2.apiVersion), tostring(j1.apiVersion))
| where rApi == '2014-04-01'
| project subscriptionId, resourceGroup, deploymentName, rType, rName, rApi, timeCreated
| order by timeCreated desc

② Template Specs を検索(配布テンプレートの“種”を叩く)

resources
| where type =~ 'microsoft.resources/templatespecs/versions'
| extend body = tostring(properties.mainTemplate)
| where body contains '"apiVersion": "2014-04-01"'
| project subscriptionId, resourceGroup, templateSpec = split(name,'/')[0], version = split(name,'/')[1]

③ Policy(DeployIfNotExists/Modify)内テンプレートを検索

resources
| where type =~ 'microsoft.authorization/policydefinitions'
| extend rule = tostring(properties.policyRule)
| where rule contains '"apiVersion": "2014-04-01"'
| project subscriptionId, name, displayName = properties.displayName

リソース グループのデプロイ履歴をポータル/CLIで直接検索

個別 RG の「デプロイ」画面でテンプレート JSON を開き、ブラウザの検索で "apiVersion": "2014-04-01" を探します。複数 RG を横断したい場合は Azure CLI が便利です。

# RG 一覧を回して、デプロイ テンプレートに含まれる v2014-04-01 の有無をチェック
for rg in $(az group list -o tsv --query "[].name"); do
  az deployment group list -g "$rg" \
    --query "[].{name:name, ts:properties.timestamp, hit: contains(string(properties.template), '\"apiVersion\": \"2014-04-01\"')}" \
    -o tsv | awk -v RG="$rg" '$3=="True"{print RG"\t"$0}'
done

サブスクリプション/管理グループ レベルのデプロイも忘れずに。

# サブスクリプション レベル デプロイ
az deployment sub list \
  --query "[].{name:name, ts:properties.timestamp, hit: contains(string(properties.template), '\"apiVersion\": \"2014-04-01\"')}" \
  -o table

# 管理グループ レベル デプロイ(必要に応じて)

az deployment mg list --management-group-id  
--query "[].{name:name, ts:properties.timestamp, hit: contains(string(properties.template), '"apiVersion": "2014-04-01"')}" 
-o table

コード/スクリプト/CI パイプラインの全社横断検索

IaC(ARM/Bicep)だけでなく、手書き REST(az rest、Invoke-RestMethod、curl)や旧 SDK で API バージョンを固定しているケースが潜みます。次のパターンをキーに全レポジトリを検索します。

  • "apiVersion": "2014-04-01"(ARM/Bicep)
  • api-version=2014-04-01(手書き REST、SDK オーバーライド)
  • 管理プレーンの URL:https://management.azure.com/ と Microsoft.Sql を併記
# ripgrep 例(Git リポジトリのルートで)
rg -n --hidden --glob '!**/bin/**' --glob '!**/obj/**' --glob '!**/dist/**' \
   -e '"apiVersion": "2014-04-01"' -e 'api-version=2014-04-01' -e 'management\.azure\.com/.*/Microsoft\.Sql'

# PowerShell 例(Windows 管理端末)
Get-ChildItem -Recurse -File -Include *.json,*.bicep,*.ps1,*.psm1,*.sh,*.yaml,*.yml,*.tf,*.groovy,*.js,*.ts,*.cs,*.java |
  Select-String -Pattern '"apiVersion": "2014-04-01"|api-version=2014-04-01|management\.azure\.com/.*/Microsoft\.Sql' |
  ForEach-Object { $_.Path + ':' + $_.LineNumber + ' ' + $_.Line.Trim() }

Azure DevOps なら「コード検索」、GitHub なら「全社 Code Search」で同条件をかけます。CI 定義(Azure Pipelines/GitHub Actions)内の az rest、curl、Invoke-RestMethod の行も重点チェックしましょう。

実行時の呼び出しを Log Analytics(AzureActivity)で検出

構成だけでなく、いま実際に誰が/どこから v2014‑04‑01 を叩いているかは Azure Resource Manager(ARM)→ Activity の経路で分かります。診断設定で Activity を Log Analytics ワークスペースに送っている場合、次のクエリで api-version を直接あぶり出せます。

// 直近 90 日(または保持期間)で v2014-04-01 を含む管理プレーン呼び出しを検索
AzureActivity
| where CategoryValue == 'Administrative'
| where Properties has 'api-version=2014-04-01'
| project TimeGenerated, Caller, ResourceGroup, ResourceProvider, OperationNameValue, ActivityStatusValue, CorrelationId, Properties
| order by TimeGenerated desc

Properties には ARM の requestUri 等が埋まります。必要に応じて parse_json(Properties) で展開し、uri のクエリ文字列から api-version を抽出しましょう。

// requestUri から api-version を抽出して確実にマッチさせる
AzureActivity
| where CategoryValue == 'Administrative'
| extend p = parse_json(Properties)
| extend requestUri = tostring(p.requestUri)
| where requestUri has 'api-version=2014-04-01'
| project TimeGenerated, Caller, requestUri, ActivityStatusValue, CorrelationId

Log Analytics 未配信の場合は、ポータルの「アクティビティ ログ」でも 操作名→JSON 表示から requestUri を手作業でナビゲートできます(保持は既定 90 日、サブスクごとに確認)。

ポータル/製品別:見つかった“犯人”の位置づけ

  • ARM/Bicep テンプレート:古い apiVersion を指定。ARG とデプロイ履歴で見つかる。
  • 手書き REST:az rest、PowerShell(Invoke-RestMethod)、curl で api-version を直書き。
  • 旧 SDK(“Track 1” 系):ApiVersion を明示または既定が古い。C#/Java/Node の管理 SDK を最新 “Track 2” に更新。
  • 自動化(Automation/Functions/Runbook):ランブック/関数のスクリプト内で REST 呼び出しを固定。
  • Policy/Template Spec/Blueprint:組織配布の“共通テンプレート”に古いバージョンが温存。

見つけた後の「移行」実務

v2014‑04‑01 は廃止済みです。利用が判明した箇所は直ちに新しい GA 版へ更新します(Microsoft.Sql の REST API は 2021‑11‑01 以降などの安定版を基準に選択し、機能要件に合わせて最新推奨へ)。加えて以下を徹底します。

  1. 差分の把握:ターゲット API 版のスキーマ差分を確認(プロパティの追加/必須化、既定値の変更、非推奨パラメータなど)。
  2. 下位互換テスト:検証サブスクリプションで PUT/GET を一通り実行。既存設定の再適用、what-if(テンプレート検証)を活用。
  3. 段階ロールアウト:RG やデプロイ スロット単位で段階適用。失敗時のロールバック計画(テンプレート/パラメータのバージョン固定)を準備。
  4. SDK 更改:管理 SDK は最新世代(Track 2、例:azure-resourcemanager-sql / Azure.ResourceManager.Sql)と最新ランタイムへ。
  5. CI/CD ゲート:PR 時に apiVersion と api-version の静的検査を必須化。

ゼロダウンタイムのためのガードレール

① Activity Log アラートで旧 API 版呼び出しを即時検知

「アクティビティ ログ → アラート ルール」で、シグナル=すべての管理操作、条件の「高度な編集」で api-version=2014-04-01 を含むときに通知するよう KQL 条件を設定(Action Group はメール/Teams/Webhook など)。

② PR/ビルドでのブロック ルール(例:GitHub Actions)

# .github/workflows/guard-old-api.yml
name: guard-old-api
on: [pull_request]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Scan for deprecated API version
        run: |
          set -e
          if rg -n -S '"apiVersion": "2014-04-01"|api-version=2014-04-01' \
               --glob '!**/bin/**' --glob '!**/obj/**' --glob '!**/dist/**' . ; then
            echo "::error::Found deprecated API version 2014-04-01"; exit 1
          fi

③ ポータル入力の予防(テンプレート化)

手動操作でのズレを防ぐため、Template Spec や Bicep モジュールに集約し、現場はパラメータ差し替えだけで運用できるようにします。

“この結果はどう読む?”(判定と次のアクション)

  • ARG/デプロイ/Template Spec/Policy が全てゼロ件:構成テンプレート由来のリスクは低い。次に AzureActivity の実行時ログで“いま”の利用がないかを確認。
  • Activity でヒット:呼び出し元(Caller・CorrelationId・requestUri)から、CI ジョブ/Runbook/アプリの該当コンポーネントへ遡及。コード検索と照合して改修・再デプロイ。
  • コードでヒット:PR を起こし api-version を更新。スキーマ差分に合わせてリクエスト本文/レスポンス処理も更改。
  • テンプレートでヒット:apiVersion を更新し、what-if 検証→検証環境にデプロイ→本番へ段階適用。

“旧 API 版を使っていたら起きること” と緊急対応

廃止済み API を呼ぶと、HTTP 4xx(未サポート API バージョン)や 404/410 による失敗が返ることがあります。CI が失敗して初めて気づくケースも多いので、以下を回避策として即日導入してください。

  • アラート化:前述の Activity Log アラートを全サブスクに適用。
  • 再実行の抑止:失敗時の自動リトライを一時停止(雪だるま式のスロットリング回避)。
  • 早期サクセス パス:API 版だけを差し替えた軽量ブランチで GET → PUT を検証し、最短の回復を図る。

現場で使えるコマンド断片集(抜粋)

Azure CLI(ARG)

# デプロイに v2014-04-01 を含むものを検索(文字列マッチ)
az graph query -q "
resources
| where type =~ 'microsoft.resources/deployments'
| extend tmpl = tostring(properties.template)
| where isnotempty(tmpl) and tmpl contains '\"apiVersion\": \"2014-04-01\"'
| project subscriptionId, resourceGroup, deploymentName=name, timeCreated=properties.timestamp
| order by timeCreated desc" -o table

PowerShell(アクティビティ ログ)

# 直近 30 日、api-version=2014-04-01 を含む管理操作を抽出
$start = (Get-Date).AddDays(-30)
Get-AzActivityLog -StartTime $start -Category Administrative |
  Where-Object { $_.Properties -like '*api-version=2014-04-01*' } |
  Select-Object EventTimestamp, Caller, OperationName, ResourceGroupName, ResourceProviderName, ActivityStatus, CorrelationId

PowerShell(RG 配下のデプロイ)

# 全 RG を走査して、テンプレート本文に v2014-04-01 が含まれるデプロイを出力
Get-AzResourceGroup | ForEach-Object {
  $rg = $_.ResourceGroupName
  Get-AzResourceGroupDeployment -ResourceGroupName $rg |
    Where-Object { $_.Properties.Template -and $_.Properties.Template.ToString().Contains('"apiVersion": "2014-04-01"') } |
    Select-Object @{N='ResourceGroup';E={$rg}}, DeploymentName, Timestamp
}

精度をさらに上げるためのコツ

  • テンプレート本文が保持されないケース:templateLink(URI 参照でのデプロイ)では本文が未格納の場合があります。その場合はリンク先のストレージ/リポジトリを直接検索します。
  • ネスト/モジュール:Bicep の module や ARM の Nested deployment で間接参照していると、親テンプレートには痕跡が残らないことがあります。Template Spec 側も必ず検索。
  • 保持期間の壁:Activity の既定保持は 90 日。長期に遡る必要があるなら、ストレージ/イベントハブにエクスポートしていた履歴を探索。
  • SDK の暗黙 API バージョン:古い SDK は既定 API が古いことがあります。依存パッケージを棚卸しし、Major の大きい最新 SDK へ置換が最短です。

チェックリスト(抜け漏れ防止に)

観点具体例確認手段完了
ARM/Bicepテンプレートの "apiVersion": "2014-04-01"ARG、RG デプロイ履歴、Template Spec□
手書き RESTapi-version=2014-04-01コード検索、CI 定義の検索□
SDK古い管理 SDK(Track 1)依存リスト、パッケージ マニフェスト□
自動化Runbook / Functions / スケジュール スクリプトスクリプト検索、Activity で発火確認□
ポリシーDeployIfNotExists のテンプレートPolicy 定義の JSON 検索□
監視旧 API 版の検知Activity Log アラート、ダッシュボード□

よくある Q&A

Q. Resource Graph の resources テーブルで apiVersion を直接フィルタできますか?
A. できません。apiVersion はリソースの“現在の状態”の属性ではなく、テンプレートの文脈でのみ使われます。microsoft.resources/deployments(デプロイ履歴)や Template Spec/Policy のテンプレート本文を検索するのが正攻法です。

Q. 0 件だったが本当に使われていないと言い切れる?
A. 現時点の構成と保持期間内の実行ログにおいては未使用と判断できます。ただし将来の再発を防ぐため、アラートと CI ゲートを常設しましょう。

Q. 推奨の API バージョンは?
A. 最新の GA 版(例:2021‑11‑01 以降)を基準に、必要機能が揃う範囲で最も新しい安定版へ更新してください。プレビュー版は長期運用に向きません。

最終まとめ(運用に組み込む)

  • 構成テンプレートは ARG とテンプレート リポジトリで 一掃。
  • 実行時の REST 呼び出しは Activity(Log Analytics)で 現行犯逮捕。
  • CI/PR ゲートとアラートで 再発ゼロ を継続証明。
  • すべてのヒットは 最新 GA 版 API に更新し、検証から本番へ段階適用。

付録:コピペで使えるクエリ/スクリプト集

ARG:ヒット件数の概要をサブスク別に集計

resources
| where type =~ 'microsoft.resources/deployments'
| extend tmpl = tostring(properties.template)
| where isnotempty(tmpl) and tmpl contains '"apiVersion": "2014-04-01"'
| summarize hits = count() by subscriptionId
| order by hits desc

ARG:Template Spec / Policy をまとめて確認

let target = '"apiVersion": "2014-04-01"';
union
( resources
  | where type =~ 'microsoft.resources/templatespecs/versions'
  | extend body = tostring(properties.mainTemplate)
  | where body contains target
  | project kind = 'TemplateSpec', subscriptionId, name ),
( resources
  | where type =~ 'microsoft.authorization/policydefinitions'
  | extend rule = tostring(properties.policyRule)
  | where rule contains target
  | project kind = 'Policy', subscriptionId, name )
| order by kind asc, name asc

Log Analytics:週次レポート(誰が叩いたか)

AzureActivity
| where TimeGenerated > ago(7d)
| where CategoryValue == 'Administrative'
| extend p = parse_json(Properties)
| extend requestUri = tostring(p.requestUri)
| where requestUri has 'api-version=2014-04-01'
| summarize calls = count() by Caller
| order by calls desc

CLI:サブスク単位で ARG クエリ → CSV 出力

az graph query -q "
resources
| where type =~ 'microsoft.resources/deployments'
| extend tmpl = tostring(properties.template)
| where isnotempty(tmpl) and tmpl contains '\"apiVersion\": \"2014-04-01\"'
| project subscriptionId, resourceGroup, deploymentName=name, timeCreated=properties.timestamp
" -o csv > hits_deployments_2014-04-01.csv

PowerShell:全ストレージ/テンプレート リンク先も探索(例)

# 例:テンプレートを外部 URI 参照で展開している場合、Blob 内も探索
$pattern = 'api-version=2014-04-01|"apiVersion": "2014-04-01"'
Get-AzStorageAccount | ForEach-Object {
  $ctx = $_ | New-AzStorageContext
  Get-AzStorageContainer -Context $ctx | ForEach-Object {
    Get-AzStorageBlob -Context $ctx -Container $_.Name |
      Where-Object { $_.Name -match '\.json$|\.bicep$|\.ps1$|\.sh$|\.yaml$|\.yml$' } |
      ForEach-Object {
        $tmp = Join-Path $env:TEMP ([System.IO.Path]::GetRandomFileName())
        Get-AzStorageBlobContent -Blob $_.Name -Container $_.ICloudBlob.Container.Name -Destination $tmp -Context $ctx -Force | Out-Null
        if (Select-String -Path $tmp -Pattern $pattern -Quiet) {
          '{0}/{1}/{2}' -f $_.ICloudBlob.StorageUri.PrimaryUri.Host, $_.ICloudBlob.Container.Name, $_.Name
        }
        Remove-Item $tmp -ErrorAction SilentlyContinue
      }
  }
}

結び

「ARG で構成の痕跡を洗う」「AzureActivity で実行犯を挙げる」「CI/アラートで二度と通さない」。この三点セットを仕組み化すれば、退職者の残した“ブラックボックス”が相手でも v2014‑04‑01 の排除は現実的です。今日から動かせるクエリとスクリプトをそのまま使って、最新の GA 版 REST API へ着実に移行してください。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次