Nginx でDigest認証を使う 

Basic認証はID/PASSをBase64エンコードしているため簡単にデコード可能でありセキュリティ面でよろしくない。
Digest認証はMD5でエンコードされるため盗聴/改ざんのリスクはBasic認証より低い。
しかしnginxは標準でDigest認証に対応していない。ソースから外部モジュールを追加してコンパイルすることで対応させることができる。

# 環境

Windows10ProのHyper-V上に下記仮想マシンを作成して検証

- CentOS 8.0.1905 
- Nginx 1.17.7

なお FirewalldとSELinuxはいずれも有効にしている

# 流れ

コマンドはすべてrootユーザで実行する

## 1. 必要なパッケージをインストール

```
# dnf install gcc pcre pcre-devel make perl httpd-tools
```

`gcc` `pcre` `pcre-devel` `make` `perl` は コンパイル&インストールで必要
`httpd-tools` はDigest認証で使うパスワードファイルを生成する `htdigest` を使うために導入

## 2. ソースのダウンロード

```
# wget "http://nginx.org/download/nginx-1.17.7.tar.gz" -O /tmp/nginx-1.17.7.tar.gz
# wget "https://github.com/atomx/nginx-http-auth-digest/archive/master.zip" -O /tmp/nginx-http-auth-digest.zip
# wget "http://zlib.net/zlib-1.2.11.tar.gz" -O /tmp/zlib-1.2.11.tar.gz
# wget "https://www.openssl.org/source/openssl-1.1.1d.tar.gz" -O /tmp/openssl-1.1.1d.tar.gz
```

上から

- Nginx本体
- Digest認証モジュール https://github.com/samizdatco/nginx-http-auth-digest
- zlib (gzip圧縮に使用)
- OpenSSL


とりあえず `/usr/local/src/` に展開する

```
# tar zxvf /tmp/nginx-1.17.7.tar.gz -C /usr/local/src/
# unzip /tmp/nginx-http-auth-digest.zip -d /usr/local/src/
# tar zxvf /tmp/zlib-1.2.11.tar.gz -C /usr/local/src/
# tar zxvf /tmp/openssl-1.1.1d.tar.gz -C /usr/local/src/
```

## 3. コンパイル&インストール

```
# cd /usr/local/src/nginx-1.17.7
# ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-openssl=/usr/local/src/openssl-1.1.1d --with-zlib=/usr/local/src/zlib-1.2.11 --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-mail --with-mail_ssl_module --with-file-aio --with-http_v2_module --with-cc-opt='-O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' --add-module=../nginx-http-auth-digest-master/
# make && make install
```

## 4. 足りないモノをいろいろ作成

自動で作成されないモノを作っていく

### 4-1. ユーザ作成

nginx実行用のユーザを作成

```
# groupadd nginx
# useradd -g nginx nginx
# usermod -s /bin/false nginx
```

### 4-2. キャッシュディレクトリ作成

```
# mkdir -p /var/cache/nginx/client_temp
```

### 4-3. 起動スクリプト作成

systemd のスクリプトも自分で作成する。

```
# cat <<EOF > /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF
```

### 4-4. ログローテート設定

logrotate.dの設定ファイルを作成する


```
# cat <<EOF > /etc/logrotate.d/nginx
/var/log/nginx/*log {
    create 0664 nginx root
    daily
    rotate 10
    missingok
    notifempty
    compress
    sharedscripts
    postrotate
        /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
    endscript
}
EOF
```


### 4-5.firewalld

外部からアクセスできないためfirewalldに許可設定を行う
HTTP, HTTPSの両方を開けておく

```
# firewall-cmd --add-service=http --zone=public
# firewall-cmd --add-service=https --zone=public
```

### 4-6. パスワードファイル作成

```
# htdigest -c /etc/nginx/.htdigest_test "test" user
Adding password for user in realm test.
New password:
Re-type new password:
```

`-c` オプション でパスワードファイルの新規作成
`"test"` の部分に realm名
`user` の部分は認証時のユーザ名

パスワードは対話式で入力を求められる

## 5. NginxにDigest認証を設定

```
# vi /etc/nginx/nginx.conf
```

お試しで `/` に設定

```
        location / {
            root   html;
            index  index.html index.htm;
            auth_digest "test";
            auth_digest_user_file /etc/nginx/.htdigest_test;
        }
```

`auth_digest` にパスワードファイル作成時に指定した realm名を入れる
`auth_digest_user_file` にパスワードファイル名を指定


## 6. Nginx起動

```
# systemctl enable nginx.service
# systemctl start nginx.service
```

## 7. 動作確認

ブラウザからアクセスすると下記のようなダイアログが表示される。
設定したユーザ名とパスワードを入力
![Image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517823/d7254754-5480-11c6-0080-be23bbaa72e3.png)

認証が通ればページが表示される

![Image4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517823/279b9fcc-1896-668c-b0c5-cd6ec79802c2.png)


ちなみに curl の場合は `-u "user:password"` に加えて `--digest` オプションを付ける

```
C:\>curl --digest -u "user:password" -I http://192.168.0.31/
HTTP/1.1 401 Unauthorized
Server: nginx/1.17.7
Date: Mon, 24 Feb 2020 04:39:39 GMT
Content-Type: text/html
Content-Length: 179
Connection: keep-alive
WWW-Authenticate: Digest algorithm="MD5", qop="auth", realm="test", nonce="39e753bf5e53538b"

HTTP/1.1 200 OK
Server: nginx/1.17.7
Date: Mon, 24 Feb 2020 04:39:40 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 24 Feb 2020 04:21:48 GMT
Connection: keep-alive
Authentication-Info: qop="auth", rspauth="0565bae4b6bfbda5513657687d318700", cnonce="66a3a2f56a85034803fdd085b686f8c3", nc=00000001
ETag: "5e534f5c-264"
Accept-Ranges: bytes

```

とりあえず動いていそう。