touch /tmp/output

サーバ関連の事とか、書けたらプログラミングの事とか

WordPress の画像を S3 にアップロードして、CloudFlare 経由で配信する

やりたかったこと

  • EC2 + RDS を使って WordPress を構築する
  • EC2 は ALB 配下にいる
  • WordPress のメディア機能からアップロードした画像を S3 に配置する
  • CloudFlare を経由して S3 の画像を表示させ、キャッシュもさせる

やったこと

Cloudflare Setup for Amazon S3 を見ながら設定

環境

やったこと

1. CloudFlare のネームサーバにドメインの設定をする

  • Type: CNAME
  • Name: 対象ドメイン名(xxx.com など)
  • Value: ALB の DNS 名(xxx-alb-xxx.ap-northeast-1.elb.amazonaws.com など)
  • TTL: Automatic
  • Status: DNS and HTTP proxy

2. サイト表示確認

ブラウザから xxx.com にアクセスして WordPress のトップページが表示されること

3. AWS S3 バケット作成

  • バケット名は画像用の CMANE と同じ名前にすること
    • 例. image.xxx.com など
  • パブリックアクセスの読み取りが行えるようにしておくこと

4. 仮想ホスト形式の URL でバケットへのアクセス確認

https://バケット名.s3-ap-northeast-1.amazonaws.com

5. CloudFlare のネームサーバに画像用のドメインの設定をする

6. WP Offload Media 設定

7. CloudFlare の SSL 設定

Crypto → SSL → Full

8. キャッシュ確認

Chromeデベロッパーツールなどで画像のレスポンスヘッダに「cf-cache-status: HIT」が出力されていれば OK

fail2ban で対象 IP アドレスの第 2 オクテット(Class B)から遮断する

概要

某国からの DDoS 攻撃を fail2ban を使って防御したので、その時の設定をメモしておきます。 (設定は鵜呑みにせずに検証はしてください。)

当初 IP アドレス単位で Ban してたのですが、アクセスが多すぎて fail2ban がメモリを使いすぎて、 SWAP が発生してしまったので、対象 IP アドレスの第 2 オクテット(Class B)から遮断しました。

環境

fail2ban のインストール

# sudo su -
# rpm -Uvh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
# yum install --enablerepo=epel fail2ban

fail2ban の用語の定義

  • filter : 対象のログパターンを正規表現で定義する
  • action : filter にマッチした際に実行されるコマンドを定義する
  • jail : 1つの filter と 1つ以上の action を組み合わせ

fail2ban の典型的なフォルダ構成

公式のドキュメントにも書いてありますが、 .conf は編集せず .local ファイルにカスタマイズしたい内容だけを設定するようにしましょう。 そうすることで、アップグレード時のマージ問題を避けられるそうです。

Every .conf file can be overridden with a file named .local. The .conf file is read first, then .local, with later settings overriding earlier ones. Thus, a .local file doesn't have to include everything in the corresponding .conf file, only those settings that you wish to override.

Modifications should take place in the .local and not in the .conf. This avoids merging problem when upgrading. These files are well documented and detailed information should be available there.

/etc/fail2ban/
├── action.d
│   ├── dummy.conf
│   ├── hostsdeny.conf
│   ├── iptables.conf
│   ├── mail-whois.conf
│   ├── mail.conf
│   └── shorewall.conf
├── fail2ban.conf ← メイン設定。編集しないこと。
├── fail2ban.local ← メイン設定をカスタマイズする場合に作成する。
├── filter.d
│   ├── apache-auth.conf
│   ├── apache-noscript.conf
│   ├── couriersmtp.conf
│   ├── postfix.conf
│   ├── proftpd.conf
│   ├── qmail.conf
│   ├── sasl.conf
│   ├── sshd.conf
│   └── vsftpd.conf
├── jail.conf ← ジェイル設定。編集しないこと。
└── jail.local ← ジェイル設定をカスタマイズする場合に作成する。

DDos 攻撃を受けた時にやったこと

1. filter の作成

テンプレートがいくつか用意されているので、似た条件の filter ファイルを探してコピーするのが間違いが少ないと思います。 今回は Apache を使用した Web サーバへのアタックだったので apache-badbots.conf をコピーして filter を作成しました。

failregex にマッチさせる条件を正規表現で設定します。 下のサンプルは Apacheアクセスログを想定してマッチ条件を書いてるので適宜置き換えてください。

/etc/fail2ban/filter.d/apache-test.conf

[Definition]

failregex = ^<HOST> -.*"GET /icons/poweredby.png.*HTTP.*".*$
ignoreregex =

2. jail.local の作成

jail.conf の設定からカスタマイズしたい項目だけを設定します。 逆に言うと、ここで設定しない項目は jail.conf の設定が反映されてしまうので、 jail.conf を読みながら jail.local を作っていくのが良いかと思います。

jail.local の中で更に DEFAULT の設定を個別の jail の設定が上書きします。

まずは 1. で作成したマッチ条件が想定した通りかを dummy アクションを使用して、 動作確認することがおすすめです。

/etc/fail2ban/jail.local

# デフォルトの設定
[DEFAULT]
# ここに設定された IP アドレスは Ban 対象外
ignoreip = 127.0.0.1/8

# filter 条件に何回マッチしたら Ban をするか
maxretry = 5

# ここで設定された時間内に "maxretry" で設定した回数マッチすると Ban される
# あまり長い時間設定するとメモリが枯渇するので 600 秒程度から開始するのが良さそう
findtime = 600

# Ban される時間を秒単位で設定
bantime  = 600

# 基本的には auto で問題ない
# 気になる人は jail.conf を読みましょう
backend  = auto

# jail 個別の設定
[apache-test]

# true にしなければ jail は開始されない
enabled  = true

# jail.conf で全てのポートが指定されているので、
# 個別に指定しないと全ポートが対象になる
port     = http,https

# フィルタ名を指定。ここでは 1. で設定したフィルタを設定。
filter   = apache-test

# アクションを設定。まずは dummy でフィルタを試す。
action   = dummy

# 対象をログを指定
logpath  = /var/log/httpd/access_log

3. fail2ban の起動

  • 起動
# service fail2ban
  • 起動している jail を確認
# fail2ban-client status
Status
|- Number of jail:  1
`- Jail list:   apache-test
  • jail 名を指定すると詳細が確認できます
# fail2ban-client status apache-test
Status for the jail: apache-test
|- Filter
|  |- Currently failed: 0
|  |- Total failed: 0
|  `- File list:    /var/log/httpd/access_log
`- Actions
   |- Currently banned: 0
   |- Total banned: 0
   `- Banned IP list:

4. ログ確認

dummy アクションは、マッチした場合はログに出力のみ行うので、filter が正しく設定されているかを確認できます。 ログが出ていないようであれば、何かしら設定が間違っているので見直ししましょう。

2018-09-16 13:55:37,229 fail2ban.filter         [3505]: INFO    Log rotation detected for /var/log/httpd/access_log
2018-09-16 13:55:37,283 fail2ban.filter         [3505]: INFO    [apache-test] Found 192.168.xxx.xxx
2018-09-16 13:55:37,571 fail2ban.actions        [3505]: NOTICE  [apache-test] Ban 192.168.xxx.xxx

ちなみにログの場所はデフォルトは SYSLOG になっているので /var/log/messages に出力されます。 ただ、それだと可読性が悪いので個別のログに出力するのが良いと思います。

rsyslog を使用しているのであれば、rsyslog の設定を追加して反映してあげましょう。 それから、ログローテートの設定は忘れずに

/etc/rsyslog.d/fail2ban.conf

if $programname startswith 'fail2ban' then /var/log/fail2ban.log
if $programname startswith 'fail2ban' then stop

5. action の作成

filter の動作確認が出来たら action を作っていきます。 filter と同様にテンプレートがいくつか用意されているので、似た条件の action ファイルを探してコピーします。

今回は iptables-allports.conf をコピーして作成しました。 今回は対象 IP アドレスの第 2 オクテット(Class B)まで遮断したかったのと、 http, https のみ Ban したかったので、actionban と actionunban を変更してます。

iptables-http-ports-class-b.conf

[INCLUDES]

before = iptables-common.conf


[Definition]

# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
#
actionstart = <iptables> -N f2b-<name>
              <iptables> -A f2b-<name> -j <returntype>
              <iptables> -I <chain> -p <protocol> -j f2b-<name>

# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
#
actionstop = <iptables> -D <chain> -p <protocol> -j f2b-<name>
             <iptables> -F f2b-<name>
             <iptables> -X f2b-<name>

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionban = <iptables> -I f2b-<name> 1 -s <ip>/16 -m multiport -p tcp --dports 80,443 -j <blocktype>

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionunban = <iptables> -D f2b-<name> -s <ip>/16 -m multiport -p tcp --dports 80,443 -j <blocktype>

[Init]

6. jail.local の action 変更

jail.local の action 部分を書き換えます。 引数の name は iptables の CHAIN 名になるので、判別しやすい名前にしましょう。

/etc/fail2ban/jail.local

action = dummy

↓↓↓ 書き換え

action = iptables-http-ports-class-b[name=ApacheTest]

7. fail2ban-client のリロード

設定に問題がなければリロードして反映します。

# fail2ban-client reload

正常に遮断が出来ているか確認を忘れずに。

# iptables -nvL
# tailf /var/log/fail2ban/fail2ban.log

8. fail2ban の自動起動 ON

正常に遮断されていることを確認できたら fail2ban の自動起動を ON にしておきます。

# chkconfig fail2ban on
# chkconfig --list fail2ban
fail2ban        0:off   1:off   2:on    3:on    4:on    5:on    6:off

unicorn を再起動せずにワーカープロセスの数を1つ増やす/減らす

概要

unicorn のワーカープロセスを変更するのに再起動していたら、
「それ、再起動しないでも出来るよ」って先輩に言われたので検証してみました。

github.com

  • TTIN - increment the number of worker processes by one
  • TTOU - decrement the number of worker processes by one

環境

実行結果

[root@localhost example]# ps auxwwf | grep -w [u]nicorn
root     23609  0.7  8.0 688632 82084 ?        Sl   14:54   0:00 unicorn_rails master -c config/unicorn.rb -D -E development
root     23619  0.0  7.2 689660 73660 ?        Sl   14:54   0:00  \_ unicorn_rails worker[0] -c config/unicorn.rb -D -E development
root     23623  0.0  7.2 689660 73864 ?        Sl   14:54   0:00  \_ unicorn_rails worker[1] -c config/unicorn.rb -D -E development
  • TTIN でワーカープロセスの数を1つ増やす
[root@localhost example]# kill -s TTIN 23609
  • ワーカープロセスは 3 つ、1つ増えた
[root@localhost example]# ps auxwwf | grep -w [u]nicorn
root     23609  0.4  8.0 688632 82096 ?        Sl   14:54   0:00 unicorn_rails master -c config/unicorn.rb -D -E development
root     23619  0.0  7.2 689660 73660 ?        Sl   14:54   0:00  \_ unicorn_rails worker[0] -c config/unicorn.rb -D -E development
root     23623  0.0  7.2 689660 73864 ?        Sl   14:54   0:00  \_ unicorn_rails worker[1] -c config/unicorn.rb -D -E development
root     23630  0.0  7.2 689660 73692 ?        Sl   14:58   0:00  \_ unicorn_rails worker[2] -c config/unicorn.rb -D -E development
  • TTIN でワーカープロセスの数を1つ減らす
[root@localhost example]# kill -s TTOU 23609
  • ワーカープロセスは 2 つ、1つ減った
[root@localhost example]# ps auxwwf | grep -w [u]nicorn
root     23609  0.3  8.0 688632 82100 ?        Sl   14:54   0:00 unicorn_rails master -c config/unicorn.rb -D -E development
root     23619  0.0  7.2 689660 73660 ?        Sl   14:54   0:00  \_ unicorn_rails worker[0] -c config/unicorn.rb -D -E development
root     23623  0.0  7.2 689660 73864 ?        Sl   14:54   0:00  \_ unicorn_rails worker[1] -c config/unicorn.rb -D -E development
  • TTIN でワーカープロセスの数を1つ増やす
[root@localhost example]# kill -s TTIN 23609
[root@localhost example]# ps auxwwf | grep -w [u]nicorn
root     23609  0.3  8.0 688632 82104 ?        Sl   14:54   0:00 unicorn_rails master -c config/unicorn.rb -D -E development
root     23619  0.0  7.2 689660 73660 ?        Sl   14:54   0:00  \_ unicorn_rails worker[0] -c config/unicorn.rb -D -E development
root     23623  0.0  7.2 689660 73864 ?        Sl   14:54   0:00  \_ unicorn_rails worker[1] -c config/unicorn.rb -D -E development
root     23638  0.0  7.2 689660 73764 ?        Sl   14:58   0:00  \_ unicorn_rails worker[2] -c config/unicorn.rb -D -E development
[root@localhost example]# kill -s QUIT 23609
[root@localhost example]# ps auxwwf | grep -w [u]nicorn
[root@localhost example]# bundle exec unicorn_rails -c config/unicorn.rb -D -E development
  • ワーカープロセスは 2 つ(設定ファイルの値)
[root@localhost example]# ps auxwwf | grep -w [u]nicorn
root     23679 22.0  6.9 676368 70204 ?        Sl   15:00   0:00 unicorn_rails master -c config/unicorn.rb -D -E development
root     23689  0.0  6.0 611860 61804 ?        Sl   15:00   0:00  \_ unicorn_rails worker[0] -c config/unicorn.rb -D -E development
root     23693  0.0  6.0 677396 61704 ?        Sl   15:00   0:00  \_ unicorn_rails worker[1] -c config/unicorn.rb -D -E development

まとめ

コマンド再起動するより断然いいですね。
注意としては設定ファイルを更新してあげないと再起動すると戻ってしまうので、
オンラインで変更したら設定ファイルの修正も忘れずに。

その他

kill コマンドについて誤解してました。
プロセスを文字通り kill するコマンドと思っていたのですが、
man コマンドの DESCRIPTION を読むと指定されたシグナルを
指定されたプロセスまたはプロセスグループに送信すると書いてあるので、
kill するだけのコマンドではないんですね。

とはいえ man コマンドの NAME だけ見ると勘違いするよね・・・

NAME kill - terminate a process

gunicorn は未検証ですがドキュメント見る限り同じことができそう。

Signal Handling — Gunicorn 19.9.0 documentation

参考

[何となく知ってたけど再確認] capistrano3-unicornがunicornに送るシグナルまとめ
検証してから先人のもっと詳しい記事を見つけました

Udemy で「手を動かしながら2週間で学ぶ AWS 基本から応用まで」 その2

www.ketancho.net

昨日の続き
今日視聴したのは下記

  • Day4-4: DBサーバの構築(失敗編)
  • Day4-5: NATGWの導入とDBサーバの構築(1)
  • Day4-6: NATGWの導入とDBサーバの構築(2)
  • Day4-7: ネットワークACLについて
  • Day4-8: ネットワーク関連の設計ポイント
  • Day4-9: Day4のまとめ

セキュリティグループとネットワーク ACL について理解が甘かったのが解ってよかった。 クラスメソッドさんの記事がわかりやすかった。公式も読んで復習だ!!

dev.classmethod.jp

docs.aws.amazon.com

Udemy で「手を動かしながら2週間で学ぶ AWS 基本から応用まで」はじめてみた

www.ketancho.net

AWS 認定ソリューションアーキテクト – アソシエイト取得してから、1年経過してしまった。 プロフェッショナル取る前に復習を兼ねて上記 Udemy の講座を受講中

前半は復習的な内容だったので 1.5 倍速で流し聴いてる。 後半は触ったことないサービスも出てくるので、手を動かしていきたい。

データベーススペシャリスト(H27年度) 勉強まとめ2(第2正規化について)

前回、第2正規化の定義として以下まとめたが、これだけだとよくわからないのでもう少しまとめる。

  • 関係Rは第1正規化されている
  • 関係Rのすべての非キー属性はRの各候補キーに完全関数従属している

完全関数従属

完全関数従属とは、関数従属性X→Yにおいて、Xのすべての真部分集合X`について、X`→Yが成立しないことを指します。

関数従属ってなに?

ある属性の値により、他の属性の値を一意に識別出来ることを、関数従属という。

例えば、社員番号と社員名 社員番号:「12345678」は、社員名:「サトウ タロウ」など一意に決まるので、 社員名は社員番号に関数従属していることになります。

部分集合ってなに?

集合 A {1 , 2 , 3}と3つの要素からできているとした場合、
{1}、{2}、{3}はもちろんAの部分集合だし、
{1,2}、{1,3}、{2,3}もAの部分集合になり、
さらに{1,2,3}も部分集合になります。

じゃあ、真部分集合ってなに?

先ほどの集合 A{1,2,3}とした時に集合A自身つまり{1,2,3}の集合を除いたもの、
つまり、{1},{2},{3},{1,2},{1,3},{2,3}が真部分集合になります

つまり、完全関数従属ってどういうこと?

例えば、下記関係"伝票"があったとします

伝票(伝票番号、顧客番号、顧客名、商品番号、商品名、数量)

商品番号に対する商品名の重複はないとした場合、この関係の候補キーは、{伝票番号,商品番号}と{伝票番号,商品名}になります。

つまり、"顧客番号","顧客名","数量"が非キー属性になります。

"数量"に対して完全関数従属かを確認

{伝票番号,商品番号}は候補キーなので、

{伝票番号,商品番号} → {数量}

は成り立ちます。では、下の場合は成り立つか?

{伝票番号} → {数量}
{商品番号} → {数量}

通常、伝票に対して数量が、商品番号に対して数量が決まることはないので、これは成り立ちませんよね?なので、完全関数従属が成り立つと言えます。
(もちろん、そういう伝票が存在しないとは言い切れないですが・・・)

"顧客名"に対して完全関数従属かを確認

例によって、{伝票番号,商品番号}は候補キーなので、

{伝票番号,商品番号} → {顧客名}

は成り立ちます。では、下の場合は成り立つか?

{伝票番号} → {顧客名}
{商品番号} → {顧客名}

通常は1つの伝票に対して1顧客が決まるので、{伝票番号} → {顧客名}が成り立つとします。
(もちろん、成り立たない伝票は世の中にあるかと思います。)

つまり、この場合は完全関数従属が成り立たないことになります。よって、第2正規化が必要となってきます。

第1正規化を第2正規化する

第1正規化を第2正規化するためには、部分関数従属を排除する必要があります。

どう排除するかというと、部分関数従属となっている関数従属を別の関係として分けていきます。

具体的には、

伝票(伝票番号、顧客番号、顧客名、商品番号、商品名、数量)

伝票明細(伝票番号商品番号、商品名、数量)
伝票(伝票番号、顧客番号、顧客名)

としてあげることで、部分関数従属を排除出来ます。

徹底攻略 データベーススペシャリスト教科書 平成27年度 (ITプロ/ITエンジニアのための徹底攻略 Tettei Kouryak)

徹底攻略 データベーススペシャリスト教科書 平成27年度 (ITプロ/ITエンジニアのための徹底攻略 Tettei Kouryak)

データベーススペシャリスト(H27年度) 勉強まとめ1(正規化理論)

データベーススペシャリストの勉強を始めたのでメモがてらまとめていきます。

正規化とは

◇正規化の目的

正規化の目的は更新時異状を排除するため

更新時異状とは?

データベースのデータが更新によって本来の状態とは違った状態になる

  1. タプル挿入時異状
  2. タプル更新(修正)時異状
  3. タプル削除時異状

◇正規化を行わない場合

更新を行わない場合は正規化の必要はない

  1. データの更新を行わない場合
  2. データの履歴を残す場合
    • 古いデータの履歴を残すなど
  3. 高速化が必要な場合
    • 正規化を行うとパフォーマンスが落ちるのであえてしない
    • その代わり更新時異状対策は別途アプリなどで行う

第1正規化

属性がすべて単一値を取ること

第2正規化

  • 関係Rは第1正規化されている
  • 関係Rのすべての非キー属性はRの各候補キーに完全関数従属している

第3正規化

  • 関係Rは第2正規化されている
  • 関係Rのすべての非キー属性はRのいかなる候補キーにも推移的に関数従属しない

ボイスコッド正規形

X→YをRの関数従属性とするとき 1. X→Yは自明な関数従属性であるか、またいは 2. XはRのスーパーキーである

第4正規化

X→→YをRの多値従属性とするとき 1. X→→Yは自明な多値従属性であるか、または 2. XはRのスーパーキーである

細かいところは後ほどまとめる。 以下、参考した書籍

徹底攻略 データベーススペシャリスト教科書 平成27年度 (ITプロ/ITエンジニアのための徹底攻略 Tettei Kouryak)

徹底攻略 データベーススペシャリスト教科書 平成27年度 (ITプロ/ITエンジニアのための徹底攻略 Tettei Kouryak)