pg_hba.confの設定について

## 環境
Vagrant
Ubuntu20.4
Postgresql12

## はじめに

PostgreSQLのpg_hba.confについての解説記事となります。pg_hba.confは、PostgreSQLに接続するときの認証について定義されている設定ファイルです。

初期設定ではつぎのような設定になっています。この設定について解説します。

```/etc/postgresql/12/main/pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             postgres                                peer
local   all             all                                     peer
host    all             all             127.0.0.1/32            md5
```

## localとhostの違い

TYPEにはlocalとhostと大きく２つの設定があります。この２つの違いの認識は重要です。

localはUNIXドメインソケットで接続する場合の設定で、hostはTCP/IPで接続する場合の設定です。UNIXドメインソケットで接続する場合は、IPアドレスは使わないで接続をします。サーバー側でコマンドを叩いてPostgreSQLに接続する場合、つぎのようにして接続します。このコマンドでは、UNIXドメインソケットで接続しています。

```
$sudo su - postgres
$psql
postgres=#
```

サーバー側からの接続であっても、つぎのように、hオプションをつけて、接続先を明示的に指定することができます。ローカル環境で接続する場合は、localhostは省略することもできます。省略すれば、UNIXドメインソケットで接続されることになるのに対し、明示的に指定すれば、TCP/IPを使って接続されることになります。

```
$sudo su - postgres
$psql -h localhost
postgres=#
```

ホスト名を指定してもIPアドレスを指定しても、どちらでも接続できます。

```
$sudo su - postgres
$psql -h 127.0.0.1
postgres=#
```

pgAdminやSSHなどを使って、クライアントからサーバーに接続する場合は、UNIXドメインソケットを使て接続することはできません。TCP/IPを使って接続することになります。つまり、クライアントから接続する場合のpg_hba.confの設定は、localではなくhostで行います。

自分の開発環境のように、仮想環境を構築していて、PostgreSQLはゲストOSで動いており、ホストOSからpgAdminを使って接続する場合は、当然TCP/IPでしか接続できません。Windows環境の場合、ODBC接続をしたがると思うのですが、当然TCP/IP接続となります。

## peerとmd5の違い

デフォルトでは、localの設定は、つぎの設定になっています。

```/etc/postgresql/12/main/pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             postgres                                peer
local   all             all                                     peer
```

Ubuntuにはvagrantユーザーでログインしており、PostgreSQLにもvagrantロールが存在している場合、つぎのコマンドで接続することができます。

```
$psql -d hoge
hoge=#
```

Ubuntuにはvagrantユーザーでログインしています。（Ubuntuにはtanaユーザーは存在していません）PostgreSQLにtanaロールが存在しています。このような環境で、tanaでログインしようとしても接続はできません。なぜかといえば、Peer認証で設定されているためです。peer認証とはUbuntuで登録されているユーザーと同じユーザーをPostgreSQLにも登録しておき、Ubuntuのログインで認証に成功していれば、PostgreSQLの認証はスルーさせてOKにする仕組みです。

```
$psql-d hoge -U tana
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  Peer authentication failed for user "tana"
```

Peer認証をパスワード認証に変更しました。

```/etc/postgresql/12/main/pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             postgres                                peer
local   all             all                                     md5
```

Ubuntuにはvagrantユーザーでログインしています。（Ubuntuにはtanaユーザーは存在していません）PostgreSQLにtanaロールが存在しているため、これで、tanaでログインができるようになりました。パスワード認証の場合は、Ubuntuに登録されていないユーザーをPostgreSQLで登録して、接続することができます。

```
$psql-d hoge -U tana
hoge=#
```

localからの接続の場合は「Peer認証（peer）」で、hostからの接続の場合は「パスワード認証（md5）」にしておいた方が、Ubuntuで登録されているユーザーと、PostgreSQLで登録されているユーザーとの区別がつきやすくなり、管理しやすくなるため、このような設定にしておいた方が分かりやすいかと思います。

自分の場合は、localからの接続の場合は「Peer認証」にし、hostからの接続の場合は「パスワード認証」にしかしないと、始めから決めつけております。その方が管理が便利であるためです。セキュリティ的にもそれほどこだわる部分ではないかと思います。

### allとユーザーの違い

接続するユーザーが複数ある場合、各ユーザーごとに接続情報を記述することもできます。

```/etc/postgresql/12/main/pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             postgres                                peer
local   all             vagrant                                 peer
local   hoge1           user1                                   peer
local   hoge2           user2                                   peer
```

しかし、つぎのように、allでひとまとめにすることもできます。

```/etc/postgresql/12/main/pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             all                                     peer
```

新しいユーザーが追加になった場合、allにしておけば、メンテナンスする必要はありませんが、各ユーザーごとに記述した場合は、都度、メンテナンスを行わなければならないことになります。また、各ユーザーごと、接続するデータベースを制限させることもできます。上記の例では、user1はhoge1にしか接続することができません。user2はhoge2にしか接続することができないようになります。

## postgresql.conf

TCP/IP接続をする場合は、**postgresql.conf**の**listen_addresses**を設定する必要があります。設定をしないと、TCP/IP接続ができないことになります。

デフォルトでは、次の設定になっています。次の設定では、localhostを指定して接続する場合に限り、TCP/IP接続が有効になります。

```/etc/postgresql/12/main/postgresql.conf
listen_addresses = 'localhost'
```

外部にあるクライアントからサーバーのIPを指定して、接続する場合は、サーバーのIPを指定する必要があります。明示的に指定しなくても、次の設定でも基本的にOKです。

```/etc/postgresql/12/main/postgresql.conf
listen_addresses = '*'
```

## 設定例

pg_hba.confの設定例を見たい場合は、公式ドキュメントに設定例が掲載されています。

https://www.postgresql.jp/document/12/html/auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF

## 補足

pg_hba.confの設定で、重要なことがあります。pg_hba.confの設定は上から下の順番に参照されるということです。重複した設定があった場合は、上の設定の方が有効になります。また、条件にマッチした設定がなかった場合は、接続ができないことになります。

## Railsからデータベースを作成する（おまけ）

RailsでPostgreSQLにデータベースを作成するコマンドがあります。

```
$rails db:create
```
このコマンドを実行すると、PostgreSQLに接続してRubyからcreate databeseというpsqlコマンドを実行していると思われます。さて、このコマンドは、UNIXドメインソケット接続をしているのか、TCP/IP接続をしているのだろうか。

断言はできませんが、恐らく、database.ymlのhostの設定で、IPを設定すればTCP/IP接続を行い、hostの設定を省略すればUNIXドメインソケット接続を行うものと想定されます。

TCP/IPで接続をする場合の設定例（その１）

```database.yml
development:
  username: hoge
  password: hoge
  host: 192.168.33.10
```

TCP/IPで接続をする場合の設定例（その２）

```database.yml
development:
  username: hoge
  password: hoge
  host: localhost
```

UNIXドメインソケットで接続をする場合の設定例

```database.yml
development:
  username: hoge
  password: hoge
```

開発環境で開発用のデータベースを作成するのであれば、どちらで接続をしても、こだわる必要はないのですが、データベースを作成する前に、pg_hba.confの設定がどうなっているか、事前に確認を行ってからdatabase.ymlを触った方がいいと言えるでよう。

例えば、pg_hba.confの設定がデフォルトの状態のままで、PostgreSQLでロールを作成しないで、peer認証でUNIXドメインソケット接続をしにいった場合は、当然コマンドエラーが出ることになります。