MongoDB における一般的な SCRAM 認証エラーのトラブルシューティング

MongoDB での SCRAM 認証トラブルシューティングをマスターしましょう。このガイドでは、接続拒否や認証失敗の一般的な原因について詳しく説明し、クライアント設定(authMechanism、authSource)の誤り、ユーザー作成の落とし穴、必要なサーバー設定に焦点を当てます。MongoDB デプロイメントを効率的に保護するための実践的な手順を学びます。

MongoDB における一般的な SCRAM 認証エラーのトラブルシューティング

MongoDB でセキュリティを設定することは、機密データを保護するために重要です。現代の MongoDB デプロイメントは、安全なパスワードベースの認証のために SCRAM(Salted Challenge Response Authentication Mechanism) に大きく依存しています。しかし、SCRAM の実装と管理は、時にイライラする接続エラーやアクセス拒否を引き起こすことがあります。

このガイドは、MongoDB で SCRAM 認証を設定または使用する際に遭遇する最も頻繁な問題を特定し、解決するための実践的なトラブルシューティングマニュアルとして役立ちます。ユーザー作成、ロール割り当て、クライアント設定に関する一般的な落とし穴を理解することで、安全なデータベースアクセスを迅速に復元できます。

MongoDB における SCRAM の理解

SCRAM は、MongoDB のパスワードベースのチャレンジレスポンス認証メカニズムです。MongoDB は長い間 SCRAM-SHA-1 をサポートしており、現代のデプロイメントでは、サーバーとクライアントの両方がサポートする場合、一般的に SCRAM-SHA-256 が使用されます。トラブルシューティングの際に覚えておくべき重要な点は、クライアントがパスワードをサーバーに直接送信せずに、パスワードを知っていることを証明するということです。

トラブルシューティングの際は、認証失敗は通常、サーバー設定ユーザー定義、またはクライアント接続構文の3つの領域のいずれかに起因することを覚えておいてください。

一般的なエラーカテゴリ 1: 接続拒否または認証失敗(クライアント側)

これは最も一般的な症状です。認証が厳格に適用されている場合、クライアントは接続できず、Authentication failed.Connection refused のようなメッセージが表示されることがよくあります。

1. 誤った認証メカニズムの指定

MongoDB デプロイメントが SCRAM を必要としているのに、クライアントが古いまたはサポートされていないメカニズム(MONGODB-CR など)を使用しようとすると、接続はすぐに失敗します。

解決策: 接続文字列またはドライバー設定で SCRAM を明示的に要求していることを確認してください。

最新のドライバーをサポートするクライアントの場合、接続文字列はしばしば認証メカニズム(authMechanism)を指定します。SCRAM-SHA-256(推奨)を使用する最新のデプロイメントの場合:

mongodb://user:password@host:27017/dbname?authSource=admin&authMechanism=SCRAM-SHA-256

ヒント: SCRAM のみに設定されたサーバーで authMechanism を省略した場合、ドライバーはデフォルトで正しく動作するはずですが、明示的に設定することで曖昧さを排除できます。

2. 間違った authSource の使用

MongoDB では、authSource パラメータはユーザーアカウントが定義されているデータベースを指定します。ユーザーが admin データベースに存在する場合に、authSource=myappdb を指定して接続すると、サーバーは資格情報を見つけることができません。

シナリオ例: ユーザー app_useradmin データベースに作成されました。

誤った接続:

mongodb://app_user:password@localhost:27017/myappdb?authSource=myappdb

正しい接続:

mongodb://app_user:password@localhost:27017/myappdb?authSource=admin

3. 認証失敗を隠すネットワークまたはバインディングの問題

時々、接続の問題が認証失敗のように見えることがありますが、実際にはネットワークバインディングの問題です。mongod インスタンスが 127.0.0.1(localhost)にのみバインドされている場合、リモートクライアントは認証を試みる前に接続拒否を受け取ります。

アクション: mongod.confnet.bindIp がクライアント IP アドレスからの接続を許可していることを確認してください(例:すべてのインターフェースの場合は 0.0.0.0、または特定の IP)。

一般的なエラーカテゴリ 2: ユーザー作成とロール割り当てのエラー

認証失敗は、多くの場合、ユーザーの作成方法や割り当てられた権限に起因します。

1. パスワードなし(または不正な形式)で作成されたユーザー

mongosh または mongo シェルを使用して有効なパスワードを提供せずにユーザーを作成しようとすると、作成プロセスが静かに失敗するか、SCRAM 経由で正常に認証できないユーザーが作成される可能性があります。

作成のベストプラクティス: 常に強力なパスワードを指定し、ユーザー作成時に推奨される SCRAM メカニズムを使用していることを確認してください。

// 最初に管理者ユーザーとして接続
use admin

// SCRAM-SHA-256 でユーザーを作成(推奨)
db.createUser(
  {
    user: "reader_role",
    pwd: passwordPrompt(), // パスワードを安全にプロンプト
    roles: [ { role: "read", db: "mydatabase" } ]
  }
)

2. ロールの欠落または誤り

よくある混乱の原因は、接続は成功したものの、ユーザーが目的の操作(例:データの読み取り、書き込み)を実行できないことです。これは認証失敗ではなく、認可 失敗であり、エンドユーザーには同様に表示されることがよくあります。

認可のトラブルシューティング:

  1. ロール割り当ての確認: 正しいデータベース(authSource)で show users を使用して、ユーザーが存在し、期待されるロールを持っていることを確認します。
  2. 継承されたロールの確認: カスタムロールを使用している場合、必要な組み込みロール(readreadWrite など)を正しく継承していることを確認します。
  3. 接続コンテキスト: ロールは、作成時に指定されたデータベース(またはクラスターレベルのロールの場合は admin DB)でのみ有効であることを覚えておいてください。

ユーザーが dbA から読み取ろうとしても、dbB にのみロールがある場合、操作は失敗します。

3. アップグレード時の SCRAM バージョンの不一致

MongoDB をアップグレードする際、古いユーザーが依然としてレガシー MONGODB-CR メカニズムを使用してマッピングされている可能性があります。サーバーが SCRAM-SHA-256 のみ を受け入れるように設定されている場合、これらの古いユーザーはログインに失敗します。

解決策: サーバー設定をアップグレードした後、既存のユーザーの認証方法を明示的に更新する必要があります。

changePassword コマンドを使用します。これにより、現在のサーバーのデフォルトを使用して再ハッシュが強制されます:

// ユーザーパスワードを更新し、必要に応じてメカニズムを暗黙的に更新
db.changePassword(
  "old_user",
  "new_secure_password",
  { authenticationDatabase: "admin" }
)

一般的なエラーカテゴリ 3: サーバー設定の問題

複数のクライアントが接続に失敗している場合、問題はおそらく mongod 設定ファイル(mongod.conf)にあります。

1. 認証が有効になっていない

認証が完全に無効になっている場合、資格情報なしで接続するクライアントは成功するか、クライアントがとにかく認証を試みると予期せずブロックされる可能性があります。逆に、認証が必要だが設定が間違っている場合、接続は失敗します。

mongod.conf のセキュリティセクションが正しく設定されていることを確認してください:

security:
  authorization: enabled

2. 誤ったインターフェースへのバインド

前述のように、net.bindIp が制限的すぎる場合、外部クライアントは認証サービスに到達できません。

mongod.conf の例:

  • ローカルアクセスのみ: bindIp: 127.0.0.1(リモート接続が失敗)
  • クラウド/内部ネットワークに推奨: bindIp: 0.0.0.0(任意のインターフェースからの接続を許可しますが、強力なファイアウォールルールが必要)

3. 認証設定の過剰指定

一部の認証停止は、明示的に指定しすぎることが原因で発生します。SCRAM-SHA-256 を強制する URI は、古いドライバーや、そのメカニズムが利用可能になる前に作成された資格情報を持つユーザーを壊す可能性があります。別の環境からコピーされたデプロイメントファイルには、このクラスターに一致しない設定が含まれている場合もあります。

最もシンプルな動作する接続文字列から始め、なぜそれらが必要かがわかっている場合にのみオプションを追加してください。現在の mongosh セッションが機能するがアプリケーションが失敗する場合は、サーバー側のユーザーを変更する前に、ドライバーのバージョンと URI オプションを比較してください。

私が最初に使用する実践的なデバッグパス

SCRAM エラーが発生した場合、一度に3つのことを変更したい衝動を抑えてください。アプリケーションと同じネットワークから実行できる最小のログインテストから始めてください。アプリケーションが Kubernetes で実行されている場合は、一時的なデバッグポッドまたはアプリケーションポッド自体に exec してください。EC2 インスタンスで実行されている場合は、ラップトップからではなく、そのインスタンスからテストしてください。

mongosh "mongodb://[email protected]:27017/myappdb?authSource=admin" --password

これがネットワークエラーで失敗した場合、パスワードはおそらくまだ関係ありません。DNS、ファイアウォールルール、サービス名、ポートマッピング、セキュリティグループ、net.bindIp を確認してください。サーバーに到達し、Authentication failed で失敗した場合は、ユーザーの場所と資格情報に進みます。

次に確認することは、ユーザーが実際にどこに存在するかです。これにより、驚くほど多くのインシデントをキャッチできます:

use admin
db.getUser("app_user")

use myappdb
db.getUser("app_user")

admin に作成されたユーザーは、authSource=admin で認証する必要があります。myappdb に作成されたユーザーは、authSource=myappdb で認証する必要があります。URI 内のデータベースパス(例:/myappdb)は、クライアントが使用したいデフォルトデータベースです。これは自動的にログイン資格情報を保存するデータベースではありません。

その後、認証と認可を分離してください。ログインが成功したということは、ユーザー名とパスワードが受け入れられたことのみを証明します。ユーザーが読み取り、書き込み、インデックス作成、管理コマンドの実行ができることを証明するものではありません。最初に無害なチェックを実行してください:

db.runCommand({ connectionStatus: 1 })

次に、サービスが必要とする正確な操作を試してください:

use myappdb
db.orders.findOne()

2番目のコマンドが権限エラーで失敗した場合、パスワードをローテーションしないでください。アプリケーションが必要とする狭いロールを付与してください。レポートサービスは通常 read を必要とし、通常のアプリケーションは多くの場合1つのデータベースに readWrite を必要とし、移行ツールはより広範な一時的な権限を必要とする場合があります。エラーを消すためだけに root やクラスターワイドロールを付与しないでください。

use myappdb
db.grantRolesToUser("app_user", [
  { role: "readWrite", db: "myappdb" }
])

また、シークレット処理の基本的な部分も確認してください。@/?#: を含むパスワードは、パーセントエンコードされていない場合、MongoDB URI を壊す可能性があります。ファイルからコピーされた環境変数には、末尾の改行が含まれている可能性があります。Kubernetes Secrets は、古いポッドが古い値でまだ実行されている間に更新される可能性があります。そのような場合、MongoDB の設定は問題ありません。アプリケーションがあなたが思っているパスワードを送信していないだけです。

ドライバーの動作も重要です。最新の MongoDB ドライバーのほとんどは、SCRAM を自動的にネゴシエートします。authMechanism=SCRAM-SHA-256 を明示的に強制する場合は、ドライバーと保存されたユーザー資格情報がそれをサポートしていることを確認してください。アップグレード中は、mongosh と実際のアプリケーションドライバーの両方でテストしてください。シェルが機能し、アプリが失敗する場合は、サーバー側のユーザーを変更する前に、ドライバーのバージョンと URI オプションを比較してください。

マネージド MongoDB には、もう1つの落とし穴があります。それは、プロバイダーのネットワークアクセスルールです。たとえば MongoDB Atlas では、有効なデータベースユーザーでも、プロジェクトのネットワーク設定で許可されていない IP アドレスからは接続できません。アプリケーションログからは、これは接続または認証の問題のように見える可能性がありますが、修正はプロバイダーのアクセスリストまたはプライベートネットワーキング設定にあります。

最も安全なトラブルシューティングのリズムは次のとおりです: ネットワーク到達可能性を証明し、ユーザーが authSource に存在することを証明し、パスワードがシェルで機能することを証明し、ロールが操作を許可することを証明し、アプリケーションドライバーの最終的な接続文字列を比較します。この順序により、1行の URI 修正を完全な資格情報のローテーションに変えることを防ぐことができます。

エラーメッセージを過信せずに読む

MongoDB クライアントエラーは有用ですが、常に必要なレベルで表現されているとは限りません。Authentication failed は、サーバーが資格情報を拒否したことを示すのに十分具体的ですが、ユーザー名が間違っているのか、パスワードが間違っているのか、authSource が間違っているのか、メカニズムのネゴシエーションが失敗したのかを常に具体的に示すわけではありません。MongoServerSelectionError は、ドライバーが適切なサーバーを見つけられなかった場合でも、アプリケーションログで認証を指している可能性があります。

アプリケーションからの適切なログ行には、サニタイズされたホスト、データベース名、認証ソース、使用されている場合はレプリカセット名、ドライバーのタイムアウトが含まれている必要があります。パスワードを含めるべきではありません。ログに「Mongo connection failed」としか表示されない場合は、次のインシデントの前にそれを改善してください。authSource=adminauthSource=app の違いは、隠すには重要すぎます。

レプリカセットの場合、MongoDB がアドバタイズするホスト名がクライアントから到達可能であることも確認してください。ローカルから本番環境へのよくある驚きは、シードホストには到達可能だが、レプリカセットがクライアントが解決できない内部名を返すことです。その後、ドライバーはサーバー選択に失敗し、最初の手動シェルコマンドが1つのノードに対して機能したため、チームは資格情報を追跡します。rs.status() を使用し、メンバー名をアプリケーションネットワークが解決できるものと比較してください。

rs.status().members.map(m => m.name)

これらの名前がプライベート DNS 名である場合、アプリケーションはそのプライベートネットワーク内で実行するか、それらを正しく解決する接続方法を使用する必要があります。フェイルオーバーの結果を理解していない限り、セカンダリまたは単一ノードに直接接続してこれをごまかさないでください。

インシデント中の安全な修正

サービスを迅速に復元する必要がある場合は、必要以上にアクセスを広げない修正を選択してください。同じロールでアプリケーションユーザーを再作成することは、いくつかの無関係な設定を編集するよりも安全な場合があります。シークレットのずれが疑われる場合はパスワードのローテーションが合理的ですが、古いポッドが古い資格情報で再試行を続けてログを埋め尽くさないように、アプリケーションのロールアウトと調整してください。

トラブルシューティングのショートカットとして認証を無効にしないでください。これにより、デプロイメント全体のセキュリティ体制が変わり、元の原因が隠れる可能性があります。緊急時のパスが必要な場合は、初期セットアップ状態で MongoDB が許可している場合にのみ、localhost 例外を介して一時的な管理者ユーザーを作成するか、マネージドプロバイダーの文書化されたリカバリプロセスを使用してください。確立されたデプロイメントでは、監査された管理アクセスを使用してください。

修正後、正確な原因を平易な言葉で書き留めてください。「ユーザーは admin に存在し、アプリは authSource=orders を使用した」は、「Mongo 認証の問題」よりもはるかに優れています。このメモは、次の環境再構築中に同じ停止が再発するのを防ぎます。

SCRAM 認証失敗のためのサマリーチェックリスト

トラブルシューティング時は、次の順序で実行してください:

  1. サーバーステータス: mongod.confsecurity.authorization が有効になっていますか?
  2. ネットワークチェック: クライアントはサーバーの IP とポートに到達できますか(netstat または telnet を使用)?
  3. クライアント URI: authMechanism=SCRAM-SHA-256 が指定されていますか(必要な場合)?
  4. authSource: authSource はユーザーが作成されたデータベースと一致していますか?
  5. ユーザーの存在: 指定された authSource データベースにユーザーは存在しますか?
  6. パスワード/ロール: パスワードは正しく、ユーザーは意図したアクションに必要な最小限のロールを持っていますか?

これらの設定ポイントを体系的にチェックすることで、MongoDB のほとんどの SCRAM 認証エラーを迅速に特定して解決できます。