1. ホーム
  2. データベース
  3. ポストグレスキュー

PostgreSQLのユーザーログイン失敗時の自動ロック解決策

2022-01-10 23:10:06

MoMo:PostgreSQLではsession_execプラグインを使用して、パスワードの確認に数回失敗すると自動的にユーザーをロックするようになっていますが、この記事ではその対処法を紹介しています。

I. プラグイン session_exec のインストールと設定

プラグインをダウンロードし、コンパイルしてインストールします。
https://github.com/okbob/session_exec

$ unzip session_exec-master.zip 
$ cd session_exec-master/
$ make pg_config=/opt/pgsql/bin/pg_config
$ make pg_config=/opt/pgsql/bin/pg_config install

postgresql.confを設定します。

session_preload_libraries='session_exec'
session_exec.login_name='login'

注:上記の最初の変数は、通常設定されるshared_preload_librariesの代わりに、session_preload_librariesを設定します。
2つ目の変数は、カスタム実装が必要なログイン関数です。

データベースサービスを再起動します。

$ sudo systemctl restart postgresql-12

第2回 カスタムログイン機能編

データベースのログから抽出したログインの失敗を保存するために、t_loginテーブルを作成します。

create table t_login
(
login_time timestamp(3) with time zone --insert time,
user_name text -- database login user,
flag int4 -- flag bit, 0 for expired data, 1 for normal status data
);

データベースのログ情報を記録するために、外部テーブルfile_fdwを使用します。
file_fdw 設定されていない場合は、次の手順を参照してください。

$ cd /opt/postgresql-12.5/contrib/file_fdw
$ make && make install

create extension file_fdw;
CREATE SERVER pglog FOREIGN DATA WRAPPER file_fdw;

外部テーブルpostgres_logを作成し、データベースログとログイン失敗情報の関連付けを行います。

CREATE FOREIGN TABLE postgres_log( 
 log_time timestamp(3) with time zone, 
 user_name text, 
 database_name text, 
 process_id integer,
 connection_from text,
 session_id text, 
 session_line_num bigint, 
 command_tag text, 
 session_start_time timestamp with time zone, 
 virtual_transaction_id text, 
 transaction_id bigint, 
 error_severity text, 
 sql_state_code text, 
 message text, 
 detail text, 
 hint text, 
 internal_query text, 
 internal_query_pos integer, 
 context text, 
 query text, 
 query_pos integer, 
 location text, 
 application_name text
) SERVER pglog 
OPTIONS ( program 'find /opt/pg_log_5432 -type f -name "*.csv" -mtime -1 -exec cat {} \;', format 'csv' );

注意事項
1. 1. /opt/pg_log_5432 を実際の環境ログディレクトリに変更する必要があります。
2. csvログのフォーマットはPGのバージョンによって異なる場合があります。PG公式ドキュメントのruntime-config-loggingセクション(http://postgres.cn/docs/12/runtime-config-logging.html)を参照してください。

ログイン機能が作成されていないため、データベースへの接続時に以下の警告メッセージが表示されます。

$ psql -Upostgres
WARNING: function "login()" does not exist
psql (12.5)
Type "help" for help.

ログイン機能loginを作成します。

create or replace function login() returns void as $$
declare
res text;
c1 timestamp(3) with time zone;
begin

--get the latest time in the current log
select login_time 
from public.t_login 
where flag = 0 
order by login_time 
desc limit 1 
into c1; 

 --insert the latest data into the t_login table
insert into public.t_login 
select log_time,user_name 
from public.postgres_log 
where command_tag='authentication' 
and error_severity= 'FATAL' 
and log_time > c1;

update public.t_login set flag = 1 where login_time > c1; 

--check if the number of failed logins is greater than 3, if greater than 3 then lock the user
for res in select user_name from public.t_login where flag = 1 group by user_name having count(*) >=3 
loop
-- Lock the user
EXECUTE format('alter user %I nologin',res); 
--open the current locked user session
EXECUTE 'select pg_catalog.pg_terminate_backend(pid) from pg_catalog.pg_stat_activity where usename=$1' using res; 
raise notice 'Account % is locked!',res;
end loop;
end;
$$ language plpgsql strict security definer set search_path to 'public';

テスト使用

テストユーザーを作成します。

create user test1 encrypted password 'XXX';

ユーザーtest1が不正なパスワードでログインに失敗したことをシミュレートします。

$ psql -h192.168.137.11 -Utest1 postgres
Password for user test1: 
psql: error: FATAL: password authentication failed for user "test1"

ログインに失敗したログを外部テーブルから表示する。

select * from postgres_log where command_tag='authentication' and error_severity= 'FATAL';

1つのデータを見ることができます。ログイン失敗のメッセージをt_loginテーブルに手動で挿入しています。

insert into t_login select log_time,user_name,0
 from postgres_log 
 where command_tag='authentication' 
 and error_severity= 'FATAL';

上記のログイン失敗テストを参照し、さらに2回テストしてください。

次に、postgresのユーザーでデータベースにログインし、t_loginテーブルのデータを見てください。

postgres=# select * from t_login;
  login_time | user_name | flag 
-------------------------+-----------+------
 2021-02-08 06:24:47.101 | test1 | 0
 2021-02-08 06:25:16.581 | test1 | 1
 2021-02-08 06:25:18.429 | test1 | 1
(3 rows)

さらに2回ログインに失敗した後、postgresユーザでデータベースにログインし、ユーザがロックアウトされたというプロンプトが表示されることをテストしてください。

[postgres@node11 ~]$ psql
NOTICE: Account test1 is locked!
psql (12.5)
Type "help" for help.

postgres=# select * from t_login;
  login_time | user_name | flag 
-------------------------+-----------+------
 2021-02-08 06:45:38.017 | test1 | 0
 2021-02-08 06:45:58.809 | test1 | 1
 2021-02-08 06:45:58.809 | test1 | 1
 2021-02-08 06:46:08.116 | test1 | 1
 2021-02-08 06:46:11.986 | test1 | 1
(5 rows)

ユーザーのロックを解除します。

update t_login set flag = 0 where user_name='test1' and flag=1;

概要

  • session_exec は、ログインに成功した後に login 関数を呼び出すことで、ログインに失敗した回数が多すぎるユーザーをロックアウトします。
  • この方法は少し面倒で、データベース接続の速度を低下させる原因となることがあります。
  • 自動ロック解除には対応していませんので、管理者ユーザーによる手動操作が必要です。

参考リンク

https://www.jb51.net/article/208018.htm

PostgreSQLのユーザーログイン失敗自動ロック対策についての記事です。PostgreSQLのログイン失敗自動ロック内容については、スクリプトハウスの過去記事を検索するか、引き続き以下の関連記事を閲覧してください。