ポートノッキングで少しだけ SSH 接続をセキュアにした

決められた順番でポートノッキングした時だけ、SSH 接続ができるようにしました。

ポートノッキングとは?

決められた順番でポートを叩くことで、あらかじめ設定してあるコマンドを実行する仕組みのことです。
今回は、ポートノッキングされた時にファイアウォール (iptables) に穴を空ける設定をしました。

逃げ道の確保

設定ミスにより、一切 SSH 接続ができなくなるといった事態を避けるために逃げ道を確保しておきます。
複数ポートで sshd を起動する、特定のネットワークからは(ポートノッキングを使わない) SSH 接続を許可するなど設定を行ってください。

knockd インストール

$ sudo apt install -y knockd

knockd 設定

設定(1)

$ sudo vi /etc/default/knockd  
START_KNOCKD=1         #knockd 自動起動
KNOCKD_OPTS="-i ens3"  #ネットワークインタフェース設定、さくらの VPS なら ens3 のはず(?)  

設定(2)
ポートノッキングに 10001/tcp, 10002/tcp, 10003/tcp を使いました。

$ sudo vi /etc/knockd.conf  
[options]  
    logfile = /var/log/knockd.log     #ログ出力設定  
  
[openSSH]  
    sequence    = 10001:tcp,10002:tcp,10003:tcp  
    seq_timeout = 5  
    command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT  
    tcpflags    = syn  
  
[closeSSH]  
    sequence    = 10003:tcp,10002:tcp,10001:tcp  
    seq_timeout = 5  
    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT  
    tcpflags    = syn  

“sequence” で設定した順番でポートノッキングすると、"command" が実行されます。
[openSSH] で SSH 通信許可ルールを追加して、[closeSSH] で SSH 接続ルールを削除しています。

iptables 設定

iptables で許可していた SSH 接続は REJECT します。

$ sudo vi /etc/iptables/rules.v4  
-A INPUT -p tcp --dport 22 -j REJECT  
$ sudo iptables-restore < /etc/iptables/rules.v4  
$ sudo iptables -L  
.....  
REJECT     tcp  --  anywhere             anywhere             tcp dpt:ssh reject-with icmp-port-unreachable  
.....  

knockd 起動

$ sudo systemctl start knockd.service  

確認

ローカル Mac から動作確認を行います。

knock インストール

ローカル Mac へ knock をインストールします。

$ brew install knock  

動作確認

ポートノッキングする前の状態を確認します。

$ nmap %remote-server%  
PORT     STATE  SERVICE  
22/tcp   closed ssh    

STATE が “closed” になっていて、SSH 接続ができない状態です。
knock コマンドで、ポートノッキングします。

$ knock -v -d 100 %remote-server% 10001:tcp 10002:tcp 10003:tcp  

STATE が “open” になっていることを確認します。

$ nmap %remote-server%  
PORT     STATE  SERVICE  
22/tcp   open   ssh  

ポートノッキングして、ポートを閉じます。

$ knock -v -d 100 %remote-server% 10003:tcp 10002:tcp 10001:tcp  
$ nmap %remote-server%  
PORT     STATE  SERVICE  
22/tcp   closed ssh  

ポートノッキング後に 10 秒間だけポートを空けるように設定

上記の設定だと明示的にポートノッキングしないと、SSH 切断後もポートが空いたままになってしまうので、ポートノッキング時に 10 秒間だけポートを空けるように設定します。
SSH 接続時のポートノッキングは、.ssh/config の ProxyCommand 設定で行えるので、組み合わせることで SSH 接続時のみポートが空くような動作になります。

knockd 設定

サーバ側の knockd 設定を以下のように変更します。

$ sudo vi /etc/knockd.conf  
[options]  
    logfile = /var/log/knockd.log  
  
[opencloseSSH]  
    sequence    = 10001:tcp,10002:tcp,10003:tcp  
    seq_timeout = 5  
    tcpflags    = syn  
    start_command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT  
    cmd_timeout = 10  
    stop_command      = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT  

ポートノッキングされると、"start_command" が実行され、10 秒 (cmd_timeout) 後に “stop_command” が実行されます。

ssh 設定

ローカル Mac の .ssh/config に “ProxyCommand” を設定することで、SSH 接続直前にポートノッキングを行います。

$ vi ~/.ssh/config  
Host %remote-server%  
  Port 22  
  ProxyCommand bash -c '/usr/local/bin/knock -d 100 %h 10001:tcp 10002:tcp 10003:tcp; sleep 1; exec /usr/bin/nc %h %p'  

このように設定することで、ポートノッキングを意識しないで SSH 接続できます。

knockd がシステムブート時に自動起動しない問題

/etc/default/knockd で自動起動設定したけど、Debian 9 では自動起動しませんでした。
どうやらバグのようです。

ということで対応

$ sudo vi /etc/systemd/system/knockd.service  
[Unit]  
Description=Port-Knock Daemon  
After=network.target  
Documentation=man:knockd(1)  
  
[Service]  
EnvironmentFile=-/etc/default/knockd  
ExecStart=/usr/sbin/knockd $KNOCKD_OPTS  
ExecReload=/bin/kill -HUP $MAINPID  
KillMode=mixed  
SuccessExitStatus=0 2 15  
ProtectSystem=full  
CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN  
  
[Install]  
WantedBy=multi-user.target  

設定を反映させます。

$ sudo systemctl daemon-reload  
$ sudo systemctl enable knockd.service  

これでシステムブート時に自動起動するようになります。

まとめ

ポートノッキングで少しだけ SSH 接続をセキュアにしました。
ポートノッキングはセキュリティ的には気休めに過ぎないので、sshd 設定はこれまで通りセキュアにしましょう。

Amazon WorkMail でメール受信

AWS SES でメール受信の続き。
* AWS SES でメール受信 - jitsu102's blog
特定の受信者のみ Amazon WorkMail で受信し、それ以外は上記エントリで設定したように S3 に保存されるようにします。
Amazon WorkMail は、1 ユーザあたり $4/月 かかります。

WorkMail 設定

  1. [WorkMail] -> [Get started] をクリック
  2. [Quick setup] をクリック
  3. [Organization name] を入力し、[Create] をクリック
  4. Organizations 画面で、[Status] が [Active] になるまで待つ
  5. [Active] になったら、[Alias] 名を選択
  6. 左メニューから [Domains] を選び、[Add domain] をクリック
  7. [Domain name] を入力し、[Add domain] をクリック
  8. TXT レコード・MX レコード・CNAME レコードが表示されるので、DNS に設定
  9. Domains 画面で、追加したドメインチェックボックスを選択し、[Set as default] をクリック
  10. 左メニューから [Users] を選び、[Create user] をクリック
  11. [User name] と [Display name] を入力し、[Next Step] をクリック
  12. [Email Address] と [Password] を入力し、[Add user] をクリック
  13. 左メニューから [Organization settings] を選ぶ
  14. [Web Application] にある URL にアクセスし、作成したユーザで WorkMail へログイン

SES 設定

  1. SES に Rule Sets が追加されているので、追加されたルールを一番最初に変更
    1.1. 追加されたルールを選択し、[Run after rule] を [Beginning] に設定
  2. 追加されたルールの [Action] に [Stop Rule Set] を追加
    1.1. WorkMail で受信するメールは、以後のルール(S3 保存)を評価しないで終了

テストメール送信

テストメールを送信し、WorkMail で受信できることを確認する。
WorkMail で受信設定したアドレス以外のメールは S3 に保存されることを確認する。

AWS SES でメール受信

承認メールとか受信するためだけに、独自ドメインでメールサーバを運用していましたが、いろいろ面倒になってきたので AWS SES を使うことにしました。
2017 年9 月時点で SES が使えるのは以下のリージョンなので、今回は US East (N. Virginia) を使うことにしました。

  • SES が使えるリージョン
    • US East (N. Virginia)
    • US West (Oregon)
    • EU (Ireland)

独自ドメインを持っていることと、DNS 設定を変更できることが前提になります。

SES メール受信設定

特定ドメイン(独自ドメイン)宛てのメールは全て S3 に保存されることになります。

  • [SES] -> [Email Receiving] -> [Rule Sets] -> [Create a Receipt Rule]

ドメイン設定(Recipients)

  1. ドメインを入力し、[Add Recipient] をクリック
  2. [Verify domain] をクリック
  3. SES がドメインを認証するための TXT レコードが表示されます。表示されたレコードを DNS へ登録します
  4. [Close] をクリック
  5. [Next Step] をクリック

受信ルール設定(Actions)

  1. [Add action] -> [S3] -> [S3 bucket] -> [Create S3 bucket]
    1.1. Bucket Name を入力して、 [Create Bucket] をクリック
  2. [Next Step] をクリック
  3. Rule name を入力して、[Next Step] をクリック
  4. 内容を確認して、[Create Rule] をクリック

テストメール送信

テストメールを送信すると、上記で作成した S3 にメールが保存されます。
ダウンロードして内容を確認します。

本文の日本語が確認できない時

S3 からメールをダウンロードして内容を確認すると、日本語が UTF-8(16進文字列) になっていて読めません。
その場合は、xxd を使うと確認できます。

$ echo -n =E3=83=86=E3=82=B9=E3=83=88 | xxd -r -p  
テスト  

SES でメール受信したら SNS 通知

頻繁に使うアドレスではないので、メール受信したら SNSGmail などに通知するようにします。

  1. [SES] -> [Email Receiving] -> [Rule Sets] -> [View Active Rule Set] -> 作成したルールを選択
  2. [Actions] -> [Add action] -> [SNS] -> [SNS topic] -> [Create SNS topic]
    1.1. Topic Name を入力して、[Create Topic] をクリック
  3. [SNS] -> [Topics] を選択し、上記で作成した Topics の ARN をクリック
  4. [Create subscription] をクリック
    1.1. Protocol に Email、Endpoint にお知らせを受信するメールアドレスを入力し、[Create subscription] をクリック
  5. Endpoint に設定したアドレスに [AWS Notification - Subscription Confirmation] というメールが届くので、[Confirm subscription] リンクをクリック
  6. [SES] の [Rule Sets] で、[Save Rule] をクリック

参考

brew update 時の Permission denied 解決方法 #Sierra

$ brew update
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
Permission denied (publickey).
fatal: Could not read from remote repository.

brew update 時に “Permission denied (publickey).” になったので、

$ ssh-add -A

で解決しました。

`brew update` gives lots of "Permission denied (publickey)" git errors · Issue #1185 · Homebrew/brew · GitHub

福岡に行ってきた

6/30(金) 〜 7/2(日)まで福岡に行ってきたので、写真とか載せておきます。

ちょうど山笠の時期 f:id:jitsu102:20170702113921j:plain

博多駅のハート型ポスト f:id:jitsu102:20170630113129j:plain

肉・ごぼう天うどん@牧のうどん f:id:jitsu102:20170630120605j:plain

暑すぎたのでビール f:id:jitsu102:20170630143815j:plain

中洲 f:id:jitsu102:20170630212713j:plain f:id:jitsu102:20170630213725j:plain

朝うどん@ウエスf:id:jitsu102:20170701085848j:plain

櫛田神社 f:id:jitsu102:20170702100922j:plain f:id:jitsu102:20170702100949j:plain f:id:jitsu102:20170702102002j:plain

櫛田神社近くの商店街 f:id:jitsu102:20170702102657j:plain f:id:jitsu102:20170702103135j:plain

STAR WARS!! f:id:jitsu102:20170702102759j:plain

住吉神社 f:id:jitsu102:20170702105446j:plain f:id:jitsu102:20170702105724j:plain

博多駅 f:id:jitsu102:20170702114022j:plain

寿司 f:id:jitsu102:20170702124123j:plain f:id:jitsu102:20170702124951j:plain