Azure SQL DatabaseでMicrosoft Entra認証がLogin failed for user ”になる原因と解決策(.NET Framework 4.8)

Azure SQL Database を Microsoft Entra 認証(旧 Azure AD)で使おうとして、DefaultAzureCredential でアクセストークンは取得できるのに、接続時だけ Login failed for user '' で失敗する――。.NET Framework 4.8 ではこの症状が起きやすく、接続文字列の認証指定とコード側のトークン注入が噛み合っていないケースが原因になりがちです。

目次

症状:トークン取得は成功するのに「Login failed for user ”」

現象としては、次のような流れになります。

  • DefaultAzureCredential で https://database.windows.net/.default のトークン取得は成功する
  • しかし SqlConnection.Open() で Microsoft.Data.SqlClient.SqlException: 'Login failed for user ''' が発生する
  • エラーメッセージ上、ユーザー名が空文字('')扱いになっている

「トークンは取れているのに、なぜログインできないのか?」と混乱しやすいのですが、ここがポイントです。

  • トークン取得が成功しても、それが “SQL 接続で使われる” とは限りません。
  • SQL の接続処理は、接続文字列(Authentication 指定)やドライバのモードに強く依存します。

結論:.NET Framework 4.8 では「Authentication=Active Directory Default」に寄せる

この問題の解決として一番安定しやすいのが、接続文字列側で Microsoft Entra 認証方式を明示し、コード側の手動トークン注入をやめることです。

やること(解決策)

  • 接続文字列に Authentication=Active Directory Default を追加する
  • connection.AccessToken にトークンを入れるコードを削除する(混在をやめる)

削除する(不要になる)コード例

次のような “取得したトークンを手動で注入する” 実装は外します。

var credential = new DefaultAzureCredential();
var tokenRequestContext = new TokenRequestContext(
    new[] { "https://database.windows.net/.default" }
);
var token = credential.GetToken(tokenRequestContext);
connection.AccessToken = token.Token;

「トークンは取れているのに失敗する」ケースほど、この “手動注入” と “接続文字列側の認証指定(または未指定)” がチグハグになっていることが多いです。

なぜ「Login failed for user ”」になるのか(原因の考え方)

Login failed for user '' は、ざっくり言うと「SQL 認証としてログインしようとしているが、ユーザー名が空」という形で失敗している状態を表します。

Microsoft Entra 認証で接続したい場合、本来は「ユーザー名・パスワード」ではなく、Entra 由来のトークンで SQL へのログイン(Federated/AAD 系のフロー)が走るべきです。

ところが、次のように “認証方式が混在” すると、ドライバの解釈がブレて期待どおりにならないことがあります。

混在パターン起きやすいこと結果として見える症状
コードで AccessToken を入れるが、接続文字列で Authentication を指定しないSQL 認証(User ID/Password)の流れで接続しようとする/トークンを使うモードに入らないLogin failed for user '' など、SQL認証っぽい失敗
接続文字列で別の Authentication を指定している(または古い例をコピペしている)ドライバ内部の認証フローと、手動注入が競合するユーザーが空、トークンが無視されたように見える等
.NET Framework 側の実装都合で、思った通りの認証経路になっていない取得は成功しても利用されない/別経路を選ぶ「取れてるのに繋がらない」状態

つまり、「トークン取得の成功」と「SQL 接続でそのトークンが使われる」は別問題です。そこで、.NET Framework 4.8 では特に“接続文字列で Authentication=Active Directory Default を明示して、ドライバに一任する”方が事故が減ります。

最小構成:.NET Framework 4.8 で動く接続例(Authentication=Active Directory Default)

以下は “混在を避ける” ことにフォーカスした最小例です。ポイントは、AccessToken を触らないことです。

接続文字列の例

Server=tcp:<サーバー名>.database.windows.net,1433;
Database=<DB名>;
Encrypt=True;
TrustServerCertificate=False;
Connection Timeout=30;
Authentication=Active Directory Default;

WordPress に貼り付ける用途を考えると1行の方が管理しやすいので、実運用では次のように整形してもOKです。

Server=tcp:<サーバー名>.database.windows.net,1433;Database=<DB名>;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Authentication=Active Directory Default;

C# コード例(AccessToken を触らない)

using System;
using Microsoft.Data.SqlClient;

public class Program
{
    public static void Main()
    {
        var connectionString =
            "Server=tcp:<サーバー名>.database.windows.net,1433;" +
            "Database=;" +
            "Encrypt=True;" +
            "TrustServerCertificate=False;" +
            "Connection Timeout=30;" +
            "Authentication=Active Directory Default;";

        using (var conn = new SqlConnection(connectionString))
        {
            conn.Open();

            using (var cmd = conn.CreateCommand())
            {
                cmd.CommandText = "SELECT SUSER_SNAME(), DB_NAME()";
                using (var reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        Console.WriteLine("SUSER_SNAME(): " + reader.GetString(0));
                        Console.WriteLine("DB_NAME(): " + reader.GetString(1));
                    }
                }
            }
        }
    }
}

「Authentication=Active Directory Default」+「AccessToken を自前で入れない」という形に揃えると、SqlClient 側が適切なフローでトークン取得〜接続まで面倒を見てくれます。

事前設定チェック(よくある設定漏れを体系的に潰す)

質問の前提として多くは対策済みでも、チーム開発や環境差で抜けがちなので、チェック表としてまとめます。特に “サーバー側で Entra 管理者が設定されているか” は最重要です。

チェック項目どこで設定するか確認ポイント
Azure SQL Server に Entra 管理者(Active Directory admin)を設定Azure Portal(SQL Server)設定されていないと、DB 側で Entra ユーザー作成や外部プロバイダー関連が詰む
DB に対象ユーザー/グループ/マネージドIDを作成SQL(master ではなく対象DB)CREATE USER ... FROM EXTERNAL PROVIDER が基本
DB ロール付与SQLdb_datareader / db_datawriter など必要最小限に
接続元 IP をファイアウォールで許可Azure Portal(SQL Server の networking)ローカル開発PC・ビルドサーバー・App Service など環境ごとに差が出る
アプリの実行環境で Entra の認証情報が取れるローカル/サーバーAzure CLI ログイン、Visual Studio サインイン、Managed Identity など

DB ユーザー作成と権限付与の例

例として、Entra ユーザー(またはグループ)を DB に作る場合の SQL は次のようになります。

-- 対象データベースで実行
CREATE USER [[email protected]] FROM EXTERNAL PROVIDER;

ALTER ROLE db_datareader ADD MEMBER [[email protected]];
ALTER ROLE db_datawriter ADD MEMBER [[email protected]];

個人ユーザーを直に割り当てるより、運用ではEntra グループを DB ユーザーとして作って、メンバー管理を Entra 側に寄せる方が権限管理が楽になります(入退社・異動・委託先の入れ替えなど)。

「Active Directory Default」とは何か(DefaultAzureCredential と混同しない)

Authentication=Active Directory Default は、SqlClient 側が “実行環境に応じて” 認証手段を選ぶ方式です。ローカル開発と本番(Azure 上)で同じコードを動かしたい場合に相性がよく、手動でトークンを注入するより事故が減ります。

実務での感覚として、次のような使い分けになります。

実行環境狙いたい認証の形おすすめの考え方
開発者PC(Visual Studio / Azure CLI)開発者のサインイン情報で接続接続文字列は Authentication=Active Directory Default、権限は Entra グループで付与
Azure App Service / Functions / VMManaged Identity で接続本番は Managed Identity を前提にし、DB 側でその ID に権限を付与する
オンプレ/他クラウドサービスプリンシパル等を使うことも証明書/シークレット管理とローテを設計し、必要なら方式を固定する

ここで重要なのは、“どの認証フローにするかを、コードと接続文字列で二重管理しない”ことです。特に .NET Framework 4.8 では、互換性や実装差の影響を受けやすく、混在が原因でドライバの挙動が読みにくくなります。

今回のハマりどころ:トークン注入と接続文字列の「二重管理」

問題の本質は次の1点に集約できます。

認証方式を「コードで手動」+「接続文字列で別方式(または未指定)」のように混在させると、期待どおりに Entra 認証として扱われず、結果的に Login failed for user '' になり得る。

実際、コード側でトークンを取れていると「認証は成功している」と錯覚しがちですが、SQL 接続で重要なのは “接続時にドライバがどの方式としてログイン処理を組み立てたか” です。

そのため、次のどちらかに寄せるのが筋が良いです。

  • 方式A(推奨):接続文字列で Authentication=Active Directory Default を指定し、ドライバに任せる
  • 方式B(上級者向け):手動で AccessToken を注入する場合は、その方式に合わせた Authentication 指定・運用設計をする

今回のケースは方式Aが最短で安定しやすい解です。

「Authentication=Active Directory Default」に寄せると何が嬉しいのか

単に “繋がる” だけでなく、運用上のメリットも大きいです。

  • 認証フローの一貫性:接続文字列が「Entra で繋ぐ宣言」になり、レビューで見落としにくい
  • 実装が薄くなる:トークン取得・更新・例外パターンの吸収をドライバに寄せられる
  • 環境差に強い:ローカルは開発者資格情報、本番は Managed Identity といった切り替えがしやすい
  • セキュリティ事故を減らす:トークンをログ出力してしまう、キャッシュして漏れる等のミスを避けやすい

特に .NET Framework 4.8 の保守案件では、「シンプルな接続文字列」+「薄いコード」に寄せる方が長期運用で効いてきます。

追加のトラブルシュート:同じ症状に見えて別原因のケース

Login failed for user '' が出たとき、まずは “混在” を疑うのが最短ですが、周辺要因が重なることもあります。切り分けしやすいように、ありがちなパターンを表にまとめます。

エラー/症状疑うポイント対処の方向性
Login failed for user ''認証方式の混在、Authentication 未指定、User ID が空のままAuthentication=Active Directory Default に寄せ、AccessToken 注入を外して統一
接続はするが権限不足(SELECT/INSERT で拒否)DB ロール付与漏れ、対象がユーザーではなくグループ/IDDB 側のユーザー作成と ALTER ROLE ... ADD MEMBER を見直す
ファイアウォール系の拒否IP許可漏れ、環境ごとに送信元が違うAzure SQL の firewall 設定を再確認(開発PC/CI/本番で分ける)
TLS/SSL 関連の例外.NET Framework 実行環境の TLS 設定、古いOS/暗号スイートEncrypt=True を前提に、OS/ランタイムの TLS 1.2 以上の前提を満たす
ローカルは繋がるが本番だけ繋がらない本番で Default の認証経路が変わっている(Managed Identity 無効など)本番環境でどの資格情報が使われる前提かを決め、Managed Identity の有効化と DB 権限を整える

「まずは認証方式を統一」→「DB 側のユーザー/ロール」→「ネットワーク(ファイアウォール)」の順に潰すと、遠回りしにくいです。

どうしても “手動トークン注入” を続けたい場合の注意点

今回の解決策は “注入コードを削除” ですが、事情があって手動注入を選びたいケースもあります(例:トークン取得を中央集権的に管理している、特殊な認証経路を通すなど)。その場合は、次の点だけは押さえてください。

  • 手動注入をするなら、接続文字列もその方式に合わせて固定する(「未指定」や「別方式」を混ぜない)
  • トークンの更新・有効期限を考慮する(長時間プロセス、バッチ、常駐アプリで特に重要)
  • 接続プールの挙動を理解する(トークンの差し替えタイミング、同一接続文字列での再利用など)
  • ログにトークンを出さない(例外ログやデバッグログに混ざる事故が起きやすい)

ただし、保守性と事故率を考えると、.NET Framework 4.8 の一般的な業務アプリでは「Authentication=Active Directory Default に寄せる」方が無難です。

本番運用でのおすすめ設計(再発防止の観点)

最後に、今回のような “繋がる/繋がらない” を繰り返さないための現実的な運用ポイントをまとめます。

権限は「個人」ではなく「グループ」か「Managed Identity」に寄せる

  • 開発・検証は Entra グループで DB ロールを付与し、メンバー管理を Entra 側に寄せる
  • 本番は可能なら Managed Identity を採用し、シークレット管理を排除する

接続文字列は “認証方式が一目で分かる” 形にする

  • Entra 認証の場合は Authentication=Active Directory Default を明示
  • SQL 認証と同居させない(同一アプリ内で両方を使う場合も、設定を明確に分ける)

切り分け用の簡易クエリを用意しておく

障害時に「誰としてログインできているか」を確認できると早いです。

SELECT
  SUSER_SNAME() AS login_name,
  ORIGINAL_LOGIN() AS original_login,
  DB_NAME() AS database_name;

アプリ側でこの結果を一時的にログに出せるようにしておくと、権限の付け間違い(ユーザー/グループ/ID の取り違え)に気付きやすくなります。

まとめ

  • DefaultAzureCredential でトークン取得が成功しても、SQL 接続でそのトークンが使われるとは限らない
  • .NET Framework 4.8 で Login failed for user '' が出るときは、認証方式の混在をまず疑う
  • 最短で安定させるなら、接続文字列に Authentication=Active Directory Default を入れて、AccessToken 手動注入コードを削除
  • 併せて、DB 側の CREATE USER ... FROM EXTERNAL PROVIDER とロール付与、ファイアウォール許可をチェックする

この記事を書いた人

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

コメント

コメントする

目次