Nginx と Apache の、Basic認証 と IP制限 の様々な設定方法まとめ (ELBの有無も考慮)

# はじめに
NginxとApacheのBasic認証と,
NginxとApacheのIP制限（ELBの有無も考慮）の設定方法についてまとめました。

AWS EC2の`Amazon Linux2`と `Windowsサーバー`２通りの設定方法もまとめています


## IP制限の前提条件
`111.111.111.111`と`222.222.222.222`は、許可したいIP
他のIPアドレスは全て拒否

`10.0.0.0/16` = ELBが設置されているvpcのIPアドレス範囲(IPv4 CIDR等)
#IP制限（ELB使用時）

### Nginx（ELB使用時）

```Nginx:nginx.conf
server {
    listen 80;
 
    set_real_ip_from 10.0.0.0/16; # ELBを設置しているVPCのIPアドレスを指定
    real_ip_header  X-Forwarded-For;

    location /制限先ディレクトリ/ {
        allow 111.111.111.111;
        allow 222.222.222.222;
        deny all;
    }
}
```
サーバーにはELBからアクセスされるため、ELBのIPをクライアントのIPに置き換える必要があります。
そのため、`set_real_ip_from`にはELBが設置されているvpcのIPアドレスを指定し、
かつ`X-Forwarded-For`にはクライアントのIPが入っているため、`real_ip_header`にその値を設定します。
ディレクトリ単位ではなく、サーバー単位で制限したい場合、`server{}`サーバー内に`allowとdeny`をいれるとよいです。
<br>

**簡易構成図**
・通常
クライアントIP(xxx...)→ELB IP(yyy...)→サーバー
サーバーは、yyy...に対してIP制限をする

・`X-Forwarded-For`使用時
クライアントIP(xxx...)→ELB IP(xxx...とyyy...)→サーバー
サーバーは、xxx...に対してIP制限する


### Apache（ELB使用時）

```apache:.htaccess
SetEnvIf X-Forwarded-For "111\.111\.111\.111" allowedip
SetEnvIf X-Forwarded-For "222\.222\.222\.222" allowedip
order deny,allow
deny from all
allow from env=allowedip
```
`X-Forwarded-For`にはクライアントIDが入っているため、許可したいIPアドレスを指定します。
また、正規表現で確認するため、ピリオドはエスケープすることが必要です。
今回は、`.httaccess`ファイル内に記載しており、.htaccessはディレクトリ毎で制限を行うことができます。
apache全体に制限したい場合、apache2.conf(httpd.conf)に記載しましょう。


# IP制限（ELB不使用）
### Nginx（ELB不使用）

```Nginx:nginx.conf
server {
    listen 80;

    allow 111.111.111.111;
    allow 222.222.222.222;
    deny all;
 
    location / {
    }
}
```
サーバー単位で制限をかけました。`allow`と`deny`を使用するのみであり、ディレクトリ単位で制限するときは、ディレクトリ内に入れるだけです。


### Apache（ELB不使用）

```apache:.htaccess
# 2.2系以前のApache
Order deny,allow
Deny from all
Allow from 111.111.111.111
Allow from 222.222.222.222

# 2.4系以降のApache
Require all denied
Require ip 111.111.111.111
Require ip 222.222.222.222
```
Apacheは、バージョンによって記載方法が異なります。`httpd -v`のコマンドで確認できます。


# Basic認証
### Nginx (すべてのアクセスに適用)
`nginx.conf`に必要事項を記載

```Nginx:nginx.conf
server {
    listen       80;

    auth_basic "Restricted";　　　　# 認証時に表示されるメッセージ
    auth_basic_user_file /etc/nginx/.htpasswd;　　# .htpasswdファイルのパス
}
```
`nginx.conf`ファイルを変更後は、文法チェックし、再起動しましょう。

```
$ nginx -t -c /etc/nginx/nginx.conf 
$ sudo nginx -s reload
```

### Nginx (一部のアクセスのみに適用)
`index.php`のみBasic認証をかけるパターンです。

```Nginx:nginx.conf
server {
    listen 80;

    location /index.php {
        auth_basic "Restricted";                   # 認証時に表示されるメッセージ
        auth_basic_user_file /etc/nginx/.htpasswd; # .htpasswdファイルのパス
    }
}
```


```
$ nginx -t -c /etc/nginx/nginx.conf 
$ sudo nginx -s reload
```
### Nginx (一部を除く、すべてのアクセスに適用)
`index.php`のみBasic認証をかけないパターンです。

```Nginx:nginx.conf
server {
    listen 80;

    auth_basic "Restricted";　　　　# 認証時に表示されるメッセージ
    auth_basic_user_file /etc/nginx/.htpasswd;　　# .htpasswdファイルのパス

    location /index.php {
        satisfy any;  # IP制限 または Basic認証のいずれかがOKなら通す設定
        allow   all;  # すべて許可
    }
}
```


```
$ nginx -t -c /etc/nginx/nginx.conf 
$ sudo nginx -s reload
```

# Basic認証 (ELB不使用)

### Apache + Windows（ELB使用しない場合、.htaccessに記入）

```apache:.htaccess
AuthUserFile C:\Apache24\htpasswd\.htpasswd
AuthGroupfile /dev/null
AuthName "TEST WEB"
AuthType Basic
require valid-user
```
### Apache + EC2（ELB使用しない場合、.htaccessに記入）

```apache:.htaccess
<RequireAny>
    AuthUserFile /home/xxxx/htpasswd/.htpasswd
    AuthName "Please enter your ID and password"
    AuthType Basic

    Require valid-user
</RequireAny>

<Files ~ "^\.(htaccess|htpasswd)$">
    Require all denied
</Files>
```
`AuthUserFile`は、Basic認証のユーザー名とパスワードを記載した`.htpasswd`ファイルのフルパスになります。
`AuthName`は、認証時に表示されるメッセージです。
`AuthType`は認証方式です。BASIC認証を使うのでBasicと記載します。
`require valid-user`とは認証された全ユーザーのアクセスを許可するという意味です。

`<Files>`は、`.htpasswd`と`.htpasswd`を見せたくありませんので、記載します。
必須ではありません。
<br>

```apache:.htpasswd
aaaaa:$apr1$pzWRunvc$tq0UpVBXVjSJjLnLM9LGY.
```
`.htpasswd`には、Basic認証時に必要なユーザー名とパスワードを`ユーザー名:ハッシュ化されたパスワード`として記載します。

[こちらのサイトでは、](https://htaccess.cman.jp/explain/basic.html)Basic認証用の`.htaccess`と`.htpasswd`ファイルを自動生成できます

`AuthGroupFile /dev/null`は、グループごとにアクセスを許可する、という指定。「/dev/null」とは、そのようなファイルは存在しないという意味。つまりグループごとでのアクセス制限はしないという意味。

サーバーによって記載するとエラーになる場合、記載しないでおきましょう。

## Apache + EC2（ELB使用しない場合、httpd.confに記入）
`Directory`を`/var/www/html`とした場合
```conf:/etc/httpd/conf/httpd.conf
<Directory "/var/www/html">
    Options FollowSymLinks
    AllowOverride All

    AuthType Basic
    AuthName "basic auth"
    AuthUserfile /etc/httpd/conf/.htpasswd
    Require valid-user
</Directory>
```
`AuthUserfile`のパスワードのパスはどこでも良い。


httpd.conf修正後、apacheを再起動しましょう。
```terminal
$ systemctl restart httpd.service
```

### Apache + Windowsサーバー（ELB使用しない場合で、httpd.confに記入）
windowsサーバーの場合上記の方法が使えなかったため、httpd.confに記入します。


Locationの詳細説明はこちら

https://httpd.apache.org/docs/2.4/ja/mod/core.html#Location

```conf:httpd.conf
#Basic Auth
<Location "/">
    AuthType Basic
    AuthName "test basic auth"
    AuthUserFile "C:\Apache24\htpasswd\.htpasswd"
    Require valid-user
</Location>
```
LocationでBasic認証したいパスを選択できます。今回は、"/"ですが、"/index.php"と記載すると、index.phpのみBasic認証がかけられます。

パスワードの作成方法は先程の方法と同様です。
.htpasswdは、適切な箇所に配置しましょう。

そして、コマンドプロンプトでapacheを再起動します。

```
C:\Apache24\bin> httpd -k restart
```

# Basic認証 (ELB使用、ヘルスチェックを通す)
## Nginx

### Nginx（ELB使用時、ヘルスチェックを通す）
全てのパスでBasic認証されます。
nginx.confに設定し、`/etc/nginx/`配下に、`.htpasswd`を設置します。
ヘルスチェックのみ、Basic認証をパスします。

```conf:nginx.conf
server {
  listen 80;

  if ($http_user_agent = "ELB-HealthChecker/*") {
    set $auth off;
  }

  location / {
    auth_basic $auth;
    auth_basic_user_file /etc/nginx/.htpasswd; # .htpasswdファイルのパス
  }
```

### Nginx（ELB使用時、特定のパスを除外）
ヘルスチェックと`/test/`パスを除き、Basic認証する設定になります。
`/etc/nginx/`配下に、`.htpasswd`を設置します。

```conf:nginx.conf
server {
  listen 80;

  if ($http_user_agent = "ELB-HealthChecker/*") {
    set $auth off;
  }

  location /test/ {
    try_files $uri $uri/ /index.php?$query_string;
    satisfy any;
    allow   all;
  }

  location / {
    auth_basic $auth;
    auth_basic_user_file /etc/nginx/.htpasswd;
  }
```
## Apache
### Apache + EC2（ELB使用時、.htaccessに記入）
ELBのヘルスチェックのみ通してあげる設定になります。

```apache:.htaccess
# リクエストURLがヘルスチェック先の場合は、アクセスを許可
SetEnvIf User-Agent "^ELB-HealthChecker.*$" healthcheck

<RequireAny>
    AuthUserFile /home/xxxxx/htpasswd/.htpasswd
    AuthName "Please enter your ID and password"
    AuthType Basic

    # いずれかの条件を満たせばアクセス可
    Require env healthcheck
    Require valid-user
</RequireAny>

<Files ~ "^\.(htaccess|htpasswd)$">
    Require all denied
</Files>
```
`Satisfy Any`は、#いずれかの条件を満たせばアクセスできるという意味です。

**Docker使用時**、`AuthUserFile`のフルパスは、サーバーではなく、Dockerのフルパスに合わせることに注意しましょう。

### Apache + Windowsサーバー（ELB使用時、httpd.confに記入）①

`healthcheck.html`ファイルのヘルスチェックを通す設定になります。

```conf:httpd.conf
# Basic Auth
<Location "/">
    AuthType Basic
    AuthName "test basic auth"
    AuthUserFile "C:\Apache24\htpasswd\.htpasswd"
    Require valid-user

    SetEnvIf Request_URI "/healthcheck.html" healthcheck

   # 以下の条件にマッチする場合はBasic認証なし
   <RequireAny>
     Require valid-user
     Require env healthcheck
   </RequireAny>
</Location>
```

### Apache + Windowsサーバー（ELB使用時、httpd.confに記入）②

`healthcheck.htmlファイルのヘルスチェックを通す`に加え
`特定のサブドメインのみルーティングする`場合、Basic認証をなしにする設定

```conf:httpd.conf
# Basic Auth
<Location "/">
    AuthType Basic
    AuthName "test basic auth"
    AuthUserFile "C:\Apache24\htpasswd\.htpasswd"
    Require valid-user

    SetEnvIf Request_URI "/healthcheck.html" healthcheck
    SetEnvIf Host "^do1.api\." host_ok

   # 以下の条件にマッチする場合はBasic認証なし
   <RequireAny>
     Require valid-user
     Require env healthcheck
     Require env host_ok
   </RequireAny>
</Location>
```

### Apache + Windowsサーバー（ELB使用時、httpd.confに記入）③

`healthcheck.htmlファイルのヘルスチェックを通す`に加え
`特定のサブドメインのみルーティングする`に加え
`特定のIPの`場合、Basic認証をなしにする設定

```conf:httpd.conf
# Basic Auth
<Location "/">
    AuthType Basic
    AuthName "test basic auth"
    AuthUserFile "C:\Apache24\htpasswd\.htpasswd"
    Require valid-user

    SetEnvIf REMOTE_ADDR 222.222.222.222 valid-ip
    SetEnvIf Request_URI "/healthcheck.html" healthcheck
    SetEnvIf Host "^do1.api\." host_ok

   # 以下の条件にマッチする場合はBasic認証なし
   <RequireAny>
     Require valid-user
     Require env healthcheck
     Require env host_ok
　　　　　　　　　　Require env valid-ip
   </RequireAny>
</Location>
```

参考文献

https://www.javadrive.jp/apache/allow/index1.html

- apacheは↑こちらの記事を参考にしました

http://kayakuguri.github.io/blog/2017/12/14/htaccess-reuire-setting/

https://qiita.com/shotets/items/17bed9029140a6d925d2

[[Linux] Nginx に Basic 認証を設定する方法](https://www.t3a.jp/blog/infrastructure/nginx-basic-auth/)
[こんばんは、X-Forwarded-For警察です](https://www.m3tech.blog/entry/x-forwarded-for)
[Apache 2.4系でIP制限の設定方法](https://ex1.m-yabe.com/archives/2154)
[Nginx で Basic 認証](https://qiita.com/kotarella1110/items/be76b17cdbe61ff7b5ca)