背景
とある仕事でお名前メールとGMOクラウドのVPSのセットアップが必要だったので、その時のセットアップのメモ
構成
ローカル:
FW:
- APサーバー: Django
- Webサーバー: Nginx
- RDB: Postgres
- 証明書: Let’s encrypt
サーバー:
- ドメイン: お名前.com
- メールサーバー: お名前メール
- メールクライアント: ThunderBird
- サーバー: GMO Cloud VPS
メールの設定
Eメールの仕組み
- Emailの仕組みは簡単に言うと、郵便の仕組みとおなじ
- 郵便で送信者を偽装できるようにEmailでも同じことができる
- 故に、SPFとDKIMとDMARC認証SPFが必要になる
ネームサーバー
レンタルサーバーRS、お名前メールを利用している場合は次のNSになり、MMレコードなどもデフォルトで設定される。
- プライマリ: ns-rs1.gmoserver.jp
- セカンダリ: ns-rs2.gmoserver.jp
セキュリティ
SPF(Sender Policy Framework)
SPFの目的は、送信者のドメインがそのメールサーバーからのメール送信を許可しているかを確認する。
- 仕組み
- ドメインのDNSにSPFレコードを設定し、そのドメインがどのIPアドレスやメールサーバーから送信を許可しているかをリスト化する
- 動作
- 受信サーバーがメールを受け取った際に、送信元のIPアドレスをSPFレコードと照合する
- 許可されているサーバーからのメールであれば「合格」と判定し、それ以外は「不合格」とする
=> メール送信者の偽装チェック
例
1
2
3
4
5
6
| - type:
- TXT
- host:
- dendroid.net
- value:
- 600v=spf1 include:_spf.onamae.ne.jp ~all
|
なお、include
は指定されたドメインの SPF レコードを取り込み、その内容を評価に含めることを意味する。
この先は次のようになっている。
1
2
3
| $ dig +short TXT _spf.onamae.ne.jp
"v=spf1 include:_netblocks1.onamae.ne.jp include:_netblocks2.onamae.ne.jp include:spf.protection.outlook.com include:_spf.maildeliver.jp +ip4:157.7.183.0/24 +ip4:210.157.19.64/26 +ip4:157.7.151.0/24 +ip4:163.44.89.0/24 +ip4:150.95.48.0/24 ~all"
|
ここにあるip4
で指定されたIPアドレスが許可されたメールサーバーとなる。
DKIM(DomainKeys Identified Mail)
DKIMの目的は、メールが送信されてから内容が改ざんされていないことを確認するためのデジタル署名を提供する事。
- 仕組み
- ドメインのDNSに公開鍵を含むDKIMレコードを設定し、メール送信時に署名(電子署名)を付加する
- この署名は送信ドメインとメールの内容に基づいて生成される
- 動作
- 受信サーバーはDKIM署名を検証し、送信元のDNSに公開鍵を問い合わせる
- 署名と公開鍵が一致する場合、メールが正当なものであり、改ざんされていないと判断される
=> メール内容の改ざん検出
例
1
2
3
4
5
6
| - type:
- TXT
- host:
- default._domainkey.xxx.net
- value:
- v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2jhFvt8dN5ZKiiZtBqZkp7GXMna+7JXl4Q4dnPAhlEILQrLSrWeJCqtJ42YTSzMO4Z6PygeJfisMJMuEg9aib4kAn3zGbSfK/NAsamgLAMFJgrNK5S18S3mvNWWMBV4YfiMmmJu0kqkGSKELyKHPeTKPdu9j2xGxuku/SsgFQYpejqvrcFDxvd1RdIhK+Yupqx8UBNRiQxRfzjgq+Ceo+X7lqZTH1GcjvI+lFYU0Xau3B2MGP//slIV36bIduYIYV7PSgYVFY6i45WlIsldmkVoDhPCe1yQH7SWta/jUHnmGLMZT7MeD/RSyh6tp23GdiF3RGQM1rzfgEdmiUqglywIDAQAB
|
これはDKIMのバージョンDKIM1
でRSA暗号されている公開鍵(base64エンコード化)の意味
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| $ echo "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2jhFvt8dN5ZKiiZtBqZkp7GXMna+7JXl4Q4dnPAhlEILQrLSrWeJCqtJ42YTSzMO4Z6PygeJfisMJMuEg9aib4kAn3zGbSfK/NAsamgLAMFJgrNK5S18S3mvNWWMBV4YfiMmmJu0kqkGSKELyKHPeTKPdu9j2xGxuku/SsgFQYpejqvrcFDxvd1RdIhK+Yupqx8UBNRiQxRfzjgq+Ceo+X7lqZTH1GcjvI+lFYU0Xau3B2MGP//slIV36bIduYIYV7PSgYVFY6i45WlIsldmkVoDhPCe1yQH7SWta/jUHnmGLMZT7MeD/RSyh6tp23GdiF3RGQM1rzfgEdmiUqglywIDAQAB" | base64 -d > dkim_pubkey.der
$ openssl rsa -inform DER -in dkim_pubkey.der -pubin -outform PEM -out dkim_pubkey.pem
$ openssl rsa -in dkim_pubkey.pem -pubin -text -noout
Public-Key: (2048 bit)
Modulus:
00:da:38:45:be:df:1d:37:96:4a:8a:26:6d:06:a6:
64:a7:b1:97:32:76:be:ec:95:e5:e1:0e:1d:9c:f0:
21:94:42:0b:42:b2:d2:ad:67:89:0a:ab:49:e3:66:
13:4b:33:0e:e1:9e:8f:ca:07:89:7e:2b:0c:24:cb:
84:83:d6:a2:6f:89:00:9f:7c:c6:6d:27:ca:fc:d0:
2c:6a:68:0b:00:c1:49:82:b3:4a:e5:2d:7c:4b:79:
af:35:65:8c:05:5e:18:7e:23:26:98:9b:b4:92:a9:
06:48:a1:0b:c8:a1:cf:79:32:8f:76:ef:63:db:11:
b1:ba:4b:bf:4a:c8:05:41:8a:5e:8e:ab:eb:70:50:
f1:bd:dd:51:74:88:4a:f9:8b:a9:ab:1f:14:04:d4:
62:43:14:5f:ce:38:2a:f8:27:a8:f9:7e:e5:a9:94:
c7:d4:67:23:bc:8f:a5:15:85:34:5d:ab:b7:07:63:
06:3f:ff:ec:94:85:77:e9:b2:1d:b9:82:18:57:b3:
d2:81:85:45:63:a8:b8:e5:69:48:b2:57:66:91:5a:
03:84:f0:9e:d7:24:07:ed:25:ad:6b:f8:d4:1e:79:
86:2c:c6:53:ec:c7:83:fd:14:b2:87:ab:69:db:71:
9d:88:5d:d1:19:03:35:af:37:e0:11:d9:a2:52:a8:
25:cb
Exponent: 65537 (0x10001)
|
この公開鍵は、受信者がメールのデジタル署名を検証するために使用される。
DMARC(Domain-based Message Authentication, Reporting, and Conformance)
DMARCの目的はSPFとDKIMの結果に基づいて、メールを受信する側がどのように扱うかを指示し、レポートを受け取る仕組み。
- 仕組み
- ドメインのDNSにDMARCポリシーを設定する
- DMARCポリシーは、SPFとDKIMの認証結果を基に、メールを受信側が「許可」「隔離」「拒否」するかを指示する
- 動作
- 受信サーバーはSPFとDKIMを検証し、DMARCポリシーに従って適切な処理を行う
- また、DMARCポリシーに基づいて、結果をドメイン所有者にレポートする
=> SPFやDKIMで認証に失敗したメールをどう扱うかの制御が可能で、不正メールの状況が分かる。
例
1
2
3
4
5
6
| - type:
- TXT
- host:
- _dmarc.xxx.net
- value:
- v=DMARC1; p=reject
|
このp=reject
はpolicy違反のメールはrejectするという意味
お名前.comでGmailだと、なぜか通らなかったので、次の設定にした。
_dmarc.dendroid.net 600 v=DMARC1; p=none
Thunderbirdの設定
ローカルの初期セットアップ
WSLを使ってローカルで鍵生成
WSL上でWindows用のファイルを生成する。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
# 任意のキー名を変数として定義
$ KEY_NAME="gmo"
$ SSH_DIR="/mnt/c/Users/xxx/.ssh"
# ディレクトリ作成と移動
$ mkdir -p $SSH_DIR
$ cd $SSH_DIR
# SSH鍵を生成
$ echo "y" | ssh-keygen -q -t rsa -N '' -f ${SSH_DIR}/id_${KEY_NAME}_rsa >/dev/null 2>&1
# 権限設定
$ chmod -R 700 $SSH_DIR
$ chmod 600 $SSH_DIR/id_${KEY_NAME}_rsa
# configファイルに設定を追加
$ cat >> config <<EOF
Host gmo
User myuser
Port 4649
HostName sub0000551573.hmk-temp.com
IdentityFile C:/Users/xxx/.ssh/id_${KEY_NAME}_rsa
EOF
$ cat $SSH_DIR/id_${KEY_NAME}_rsa.pub
|
なお、userとportの設定は後でVPSの中でするので、最初はコメントアウトでOK。
また、表示された公開鍵は後でVPSで追加する。
Windows側での非公開鍵の権限変更
WSL側でマウントしているWindowsのファイルのパーミッションの変更は厳しいので、PowerShellを利用する。
まずは現在の権限の確認。
1
2
3
4
5
6
| PS C:\Users\xxx> icacls "C:\Users\xxx\.ssh\id_gmo_rsa"
C:\Users\xxx\.ssh\id_gmo_rsa NT AUTHORITY\SYSTEM:(F)
BUILTIN\Administrators:(F)
DESKTOP-017FR51\xxx:(F)
Successfully processed 1 files; Failed processing 0 files
|
つまり、次となっている。
- NT AUTHORITY\SYSTEM: フルコントロール ((F))
- BUILTIN\Administrators: フルコントロール ((F))
- DESKTOP-017FR51\xxx: フルコントロール ((F))
(念のため、id_gmo_rsaのバックアップをとって) SYSTEMとAdminの権限を抜く。
1
2
3
| PS C:\Users\xxx> icacls "C:\Users\xxx\.ssh\id_gmo_rsa" /remove "NT AUTHORITY\SYSTEM" "BUILTIN\Administrators"
processed file: C:\Users\xxx\.ssh\id_gmo_rsa
Successfully processed 1 files; Failed processing 0 files
|
継承されたアクセスを無効化する。
1
2
3
4
| PS C:\Users\xxx> icacls "C:\Users\xxx\.ssh\id_gmo_rsa" /inheritance:r
processed file: C:\Users\xxx\.ssh\id_gmo_rsa
Successfully processed 1 files; Failed processing 0 files
|
再度、権限の確認。
1
2
3
4
| PS C:\Users\xxx> icacls "C:\Users\xxx\.ssh\id_gmo_rsa"
C:\Users\xxx\.ssh\id_gmo_rsa DESKTOP-017FR51\xxx:(F)
Successfully processed 1 files; Failed processing 0 files
|
接続テスト。
1
| PS C:\Users\xxx\.ssh> ssh gmo
|
WindowsからのSSHの接続テスト
/mnt/c/Users/xxx/.ssh/config
の設定を使ったVSCocdeのリモートエクスプロラーのSSHで接続する。
VPSの初期セットアップ
最初の接続
GMOから来たID、PWで接続する。
1
| $ ssh root@subXXXXXX.hmk-temp.com
|
user追加
作業用ユーザーの追加。
1
2
| # adduser myuser
# usermod -aG sudo myuser
|
userのswitch
今後はmyuser
で操作する。
以後rootは使わない。
myuserの初期設定
editorの設定
.bashrc
に次を追加。
もしくは、vim.basic
(basicの方が軽い)。
1
| $ sudo update-alternatives --set editor /usr/bin/vim.basic
|
公開鍵の追加
次の手順でインスタンスに公開鍵を追加する。
1
2
3
4
| $ mkdir -p ~/.ssh
$ chmod 700 ~/.ssh
$ echo "ssh-rsa xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" >> ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/authorized_keys
|
これ以降は非公開鍵で認証してSSHをする。
定番
パッケージの更新
システムの全更新。
1
| $ apt update && sudo apt upgrade -y
|
タイムゾーン
タイムゾーンの設定。
1
2
3
| $ sudo dpkg-reconfigure tzdata
$ cat /etc/timezone
Asia/Tokyo
|
システム情報確認
ディスク
/dev/vda1
がディスクパーテーションなので、それを確認すればOK。
1
2
3
| $ df -h /
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 50G 6.0G 41G 13% /
|
メモリ
1
2
3
4
| $ free -h
total used free shared buff/cache available
Mem: 961Mi 459Mi 72Mi 2.0Mi 429Mi 345Mi
Swap: 1.0Gi 7.0Mi 1.0Gi
|
CPU
CPUの構成(2コア、2.1GHz)
1
2
3
4
5
6
7
8
9
10
11
| $ lscpu | head -n 10
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 40 bits physical, 48 bits virtual
CPU(s): 2
On-line CPU(s) list: 0,1
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 2
NUMA node(s): 1
|
使用率
1
2
| $ top -bn1 | grep 'Cpu(s)'
%Cpu(s): 2.9 us, 5.9 sy, 0.0 ni, 91.2 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
|
それぞれのCPU時間の意味:
- 高いとCPU使用率が高い
- 高いとCPU使用率が低い
- ni: ナイス値が変更されたユーザー
- id: アイドル
- wa: I/O 待ち時間
- hi: ハードウェア割り込み
- si: ソフトウェア割り込み
- st: ステール時間
NOTE: ナイス値(Nice Value)は、プロセスの優先度を調整するためのパラメータ
セキュリティ対策
ポートの確認
空いているポートの確認。
53(DNSリゾルバ)、22(SSH)と、40983のエフェメラルポートが空いている。
1
2
3
4
5
6
7
| $ sudo ss -tuln
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 1024 127.0.0.1:40983 0.0.0.0:*
tcp LISTEN 0 128 [::]:22 [::]:*
|
ちなみに、40983はcode-384fというCOMMANDだった。
1
2
3
4
5
6
7
| $ sudo lsof -i :40983
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 8838 myuser 10u IPv4 161552 0t0 TCP localhost:57754->localhost:40983 (ESTABLISHED)
code-384f 8857 myuser 10u IPv4 161546 0t0 TCP localhost:40983 (LISTEN)
code-384f 8857 myuser 11u IPv4 162577 0t0 TCP localhost:40983->localhost:57754 (ESTABLISHED)
|
その詳細は、インスタンス内のvscodeのプロセスだった。
(SSHをVSCode経由でつないでいる)
1
2
3
| $ ps -p 8857 -o comm,cmd
COMMAND CMD
code-384ff7382d /home/myuser/.vscode-server/code-384ff7382de624fb94dbaf6da11977bba1ecd427 command-shell --
|
ファイアウォールの設定
ファイアウォールの設定。
1
2
3
| $ sudo ufw allow OpenSSH
$ sudo ufw allow 80/tcp # HTTP
$ sudo ufw allow 443/tcp # HTTPS
|
有効化
状態確認
1
2
3
4
5
6
7
8
9
10
11
| $ sudo ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
|
SSHの認証を強化
1
| $ sudoedit /etc/ssh/sshd_config
|
次の変更を行う。
- SSHポートの変更: デフォルトの22から他のポートに変更する
- rootの直接ログインを禁止
- パスワード認証を無効にし、公開鍵認証に切り替える
1
2
3
4
5
| Port 4649
PermitRootLogin no
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
|
その後4649
を公開。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| $ sudo ufw allow 4649
$ sudo ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
4649 ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
4649 (v6) ALLOW Anywhere (v6)
|
再起動して4649
から接続テスト。
1
| $ systemctl restart sshd
|
22を無効化してリロード。
1
2
| $ sudo ufw deny 22
$ sudo ufw reload
|
今後は4649
から接続する。
また、jail.localを更新する。
1
2
| $ sudo systemctl restart fail2ban
$ sudo ufw reload
|
fail2ban
不正アクセス対策にfail2banでインストールする。
1
2
| $ sudo apt install fail2ban
$ sudo systemctl enable fail2ban
|
jail.local
にUFW用の設定を追加する。
1
| $ sudoedit /etc/fail2ban/jail.local
|
設定の中味。
1
2
3
4
5
6
| [DEFAULT]
banaction = ufw
[sshd]
enabled = true
port = 4649
|
再起動。
1
| $ sudo systemctl restart fail2ban
|
チェック
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| $ sudo systemctl status fail2ban
● fail2ban.service - Fail2Ban Service
Loaded: loaded (/lib/systemd/system/fail2ban.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2024-10-28 20:51:40 JST; 11min ago
Docs: man:fail2ban(1)
Process: 51516 ExecStartPre=/bin/mkdir -p /run/fail2ban (code=exited, status=0/SUCCESS)
Main PID: 51517 (f2b/server)
Tasks: 5 (limit: 1044)
Memory: 12.0M
CGroup: /system.slice/fail2ban.service
└─51517 /usr/bin/python3 /usr/bin/fail2ban-server -xf start
Oct 28 20:51:40 sub0000551573.hmk-temp.com systemd[1]: Starting Fail2Ban Service...
Oct 28 20:51:40 sub0000551573.hmk-temp.com systemd[1]: Started Fail2Ban Service.
Oct 28 20:51:40 sub0000551573.hmk-temp.com fail2ban-server[51517]: Server ready
|
1
2
3
4
| $ sudo fail2ban-client status
Status
|- Number of jail: 1
`- Jail list: sshd
|
Docker設定
Dockerのセットアップ
念のため、古いDockerの削除。
1
| $ sudo apt-get remove docker docker-engine docker.io containerd runc
|
Dockerのインスコ。
1
| $ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
|
Dockerの公式GPGキーを追加
1
| $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
Dockerのリポジトリを設定
1
| $ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
Docker Engineをインストール
1
2
| $ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
|
正常にDockerがインスコされた事を確認。
1
2
| $ sudo docker --version
Docker version 27.3.1, build ce12230
|
Docker Composeのインスコ
最新バージョンのDocker Composeをダウンロードしてインストール
1
| $ sudo curl -SL https://github.com/docker/compose/releases/download/v2.30.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
|
実行権限の追加
1
| $ sudo chmod +x /usr/local/bin/docker-compose
|
インスコの確認
1
2
| $ docker-compose --version
Docker Compose version v2.30.1
|
非rootユーザーでの実行設定
1
| $ sudo usermod -aG docker ${USER}
|
一旦グループを変更(もしくは再起動)
チェック
1
2
| $ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
|
Githubの設定
前提
VPSからコードをDlするにはいくつかの方法がある。
- UserのSSH Keyの設定
- RepositoryのDeploy keyの設定
- Github Appsの設定
今回はDeploy Keyを使用する。
VPS内でSSHの設定
1
2
3
| $ wget https://gist.githubusercontent.com/3265/54d0339408e8cd1898af6694b983736f/raw/1338df8b11fb851e429c65bf8e721451ed795e40/github.sh
$ sudo chmod +x github.sh
$ ./github.sh myrepo
|
Repository > Deploy keysから公開鍵を追加する。
1
2
| $ ssh -T git@myrepo
Hi xxx/xxx! You've successfully authenticated, but GitHub does not provide shell access.
|
これで接続ができたので、クローンする。
1
| $ git clone git@dendroid:xxx/xxx.git
|
Pythonの環境
依存パッケージをインストール
1
2
3
| $ sudo apt install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
xz-utils tk-dev libffi-dev liblzma-dev python-openssl git
|
Pyenvのインストール
1
| $ curl https://pyenv.run | bash
|
bashrc
の更新
1
2
3
| export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
|
再度読み込み
チェック
1
2
| $ pyenv --version
pyenv 2.4.17
|
Poetryのインストール
1
| $ curl -sSL https://install.python-poetry.org | python3 -
|
.bashrc
でパスを通す。
1
| export PATH="$HOME/.local/bin:$PATH"
|
有効化
チェック
1
2
| $ poetry --version
Poetry (version 1.8.4)
|
Pythonのインストール
使うPythonのインストール。
1
2
| $ pyenv install 3.6.0
$ pyenv install 3.11.0
|
確認
1
2
3
4
| $ pyenv versions
* system (set by /home/myuser/.pyenv/version)
3.6.0
3.11.0
|
globalを変更(開発時はローカルを変更する)
1
2
3
4
5
6
7
| $ pyenv global 3.11.0
$ which python
/home/myuser/.pyenv/shims/python
$ python --version
Python 3.11.0
|
globalのpythonを3.11.0に変更したので、それでインストールする。
1
2
3
4
| $ pip install pip-tools
$ which pip-compile
/home/myuser/.pyenv/shims/pip-compile
|
Postgresの設定
psqlのインストール
1
| $ sudo apt-get install postgresql-client
|
cliのインストール
参考文献