Redis NOPERMエラーの修正: ユーザーにコマンド実行権限がない(ACL)

intermediate🔴 Redis2026-05-05| Redis 6.0以降(Linux/macOS/Windows WSL)、任意のクライアント(redis-cli、Jedis、ioredis、redis-py)

Error Message

NOPERM this user has no permissions to run the 'get' command
#redis#acl#セキュリティ#noperm

エラーの内容

Redisに対してコマンドを実行すると、次のようなエラーが返ってきます:

127.0.0.1:6379> GET mykey
(error) NOPERM this user has no permissions to run the 'get' command

またはアプリケーションログから:

ReplyError: NOPERM this user has no permissions to run the 'get' command

これはRedis ACL(アクセス制御リスト)が正常に機能している証拠です。Redis 6.0(2020年4月リリース)で導入されたこの機能により、クライアントが認証したユーザーには当該コマンドの実行権限がないか、そのキーパターンへのアクセスが許可されていません。

原因

Redisへのすべての接続は、何らかのユーザーとして認証されます。明示的に設定した名前付きユーザーか、認証情報が送信されない場合は暗黙のdefaultユーザーです。各ユーザーには、実行できるコマンド、アクセスできるキーパターン、使用できるpub/subチャンネルを制御するACLルールがあります。制限に引っかかると、RedisはNOPERMを返します。

よくある原因:

  • aclfileまたはACL SETUSERdefaultユーザーが制限されている
  • 専用のアプリユーザーが作成されたが、書き込み権限のみ(または設定者によっては読み取り権限のみ)が付与されている
  • ユーザーにコマンドのアクセス権はあるが、キーが許可されたパターンに一致しない(例:cache:*キーのみ許可)
  • 最近のセキュリティ強化作業で、既存ユーザーから広範なコマンドアクセスが削除された

ステップ1:接続中のユーザーを確認する

まずここから始めます。セッションでアクティブなユーザーを確認しましょう:

127.0.0.1:6379> ACL WHOAMI
"appuser"

defaultと表示された場合、クライアントが認証情報を送信していないため、未認証で接続しています。名前付きユーザーが表示された場合、そのユーザーのACLルールがブロックの原因です。

ステップ2:ユーザーのACLルールを確認する

127.0.0.1:6379> ACL GETUSER appuser
 1) "flags"
 2) 1) "on"
 3) "passwords"
 4) 1) "...(hashed)"
 5) "commands"
 6) "+set -get"
 7) "keys"
 8) "cache:*"
 9) "channels"
10) "*"

2つのフィールドに注目します。commandsは許可されている内容を示します。上記の例では、+set -getSETが許可されているがGETが明示的に拒否されていることを意味します。次にkeysを確認します。コマンドが許可されていても、ユーザーがcache:*のような特定のキーパターンに制限されている場合があります。

全ユーザーを一覧表示するには:

127.0.0.1:6379> ACL LIST
1) "user default on nopass ~* &* +@all"
2) "user appuser on #abc123... ~cache:* +set -get"

ステップ3:不足している権限を付与する

管理者ユーザー(+@allまたは少なくとも+aclを持つユーザー)で接続し、ACL SETUSERを使ってルールを修正します。

特定のコマンドを許可する

ACL SETUSER appuser +get

コマンドカテゴリを許可する(例:すべての読み取りコマンド)

ACL SETUSER appuser +@read

すべてのコマンドを許可する(信頼できる内部サービスのみ)

ACL SETUSER appuser +@all

特定のキーパターンを許可する

ACL SETUSER appuser ~cache:* ~session:*

完全な例 — 読み取り専用ユーザーをゼロから作り直す

ACL SETUSER readonly_app on >SecurePass123 ~* +@read

これにより、以下の設定でユーザーが作成(または上書き)されます:

  • 有効化済み(on
  • パスワードはSecurePass123
  • 全キーパターンにアクセス可能(~*
  • すべての読み取りコマンドを実行可能(+@read)— GETMGETLRANGESMEMBERSHGETなど

ステップ4:ACLの変更を永続化する

ACL SETUSERはメモリ上の状態のみを更新します。Redisを再起動すると、すべての変更が元に戻ります。変更を永続化するには2つの方法があります:

オプションA:ACLファイルを使用する(推奨)

redis.confに以下を追加:

aclfile /etc/redis/users.acl

次に、現在のルールをディスクに書き出します:

127.0.0.1:6379> ACL SAVE

Redisはすべてのユーザールールをそのファイルに書き込み、再起動時にそこから読み込みます。

オプションB:redis.confに直接記述する

設定ファイルにユーザールールを直接追加します:

user appuser on >SecurePass123 ~cache:* +@read +set

ファイルを保存した後、Redisを再起動してください。

ステップ5:修正を確認する

ユーザーのルールを再度取得して、コマンドが正しく設定されているか確認します:

127.0.0.1:6379> ACL GETUSER appuser
...
 5) "commands"
 6) "+@read +set"

次に、失敗していたコマンドを実行します:

127.0.0.1:6379> AUTH appuser SecurePass123
OK
127.0.0.1:6379> GET mykey
"hello"

エラーが解消されました。ACLログで最近の拒否履歴を確認することもできます。他にブロックされているものがあるか不明な場合に役立ちます:

127.0.0.1:6379> ACL LOG
1) 1) "count"
   2) (integer) 3
   3) "reason"
   4) "command"
   5) "context"
   6) "toplevel"
   7) "object"
   8) "get"
   9) "username"
  10) "appuser"
  ...

トラブルシューティングが完了したらログをクリアします:

ACL LOG RESET

補足Tips

コマンドカテゴリを使えば入力が大幅に減る

個別のコマンドを列挙する代わりに、Redisではカテゴリ単位で権限を一括付与できます:

  • +@read — GET、MGET、LRANGE、SMEMBERS、HGETなど
  • +@write — SET、DEL、LPUSH、SADD、HSETなど
  • +@string — 文字列に関するすべてのコマンド
  • +@hash — ハッシュに関するすべてのコマンド
  • +@dangerous — FLUSHDB、CONFIG、DEBUGなど(厳重に制限すること)

利用可能なカテゴリをすべて表示するには:

ACL CAT

特定のカテゴリに含まれるコマンドを確認するには:

ACL CAT read

最小権限の原則 — 本当に守ること

エラーを解消するためだけに+@allを付与するのは避けましょう。楽な方法ではありますが、ACLの意味がなくなってしまいます。キューからジョブを取り出すバックグラウンドワーカーであれば、+@read +blpop +brpopだけで十分です。アプリが実際に何を呼び出しているか調べましょう。ACL LOGが役立ちます。そして必要な権限だけを付与してください。

本番環境ではdefaultユーザーを無効化する

未認証の接続にはいかなるアクセスも許可すべきではありません。本番環境での標準的な設定:

user default off nopass ~* -@all

これにより、アプリが認証情報を送り忘れた場合、フル権限でこっそり接続されるのではなく、明確なエラーが返ります。実際のアクセスはすべて名前付きユーザーで行います。

本番適用前にカテゴリをテストする

あるコマンドが+@readに含まれていると思っていたら、実は+@string+@sortedsetだったということはよくあります。本番ユーザーにルールを適用する前に、ACL CAT <category>を使ってターミナルで確認するようにしています。10秒もあれば確認でき、深夜のデバッグを何度も救ってくれます。

Related Error Notes