うまいぼうぶろぐ

linuxとhttpdとperlのメモ

BIG-IP iruleでクライアントがTLS 1.1以下でアクセスしたときに別poolに振り分ける

PCI-DSS 絡みとかでTLS 1.1 以下が徐々に閉鎖されていっているなか、あらかじめWebページで告知したとしてもやはり接続してくるクライアントは一定数いてそうなので救済策を考えて見た。


TLS のバージョンはCLIENTSSL_HANDSHAKE eventで SSL::cipher version で取得できる。
(SSL3.0以下はclient-ssl profile で落としているのでここでは考慮しない)

VirtualServer にはdefaultでpoolが既に割り当てられているとする。

  • irule
when CLIENTSSL_HANDSHAKE {
    if { ( [SSL::cipher version] equals "TLSv1" ) or ( [SSL::cipher version] equals "TLSv1.1" ) } {
        pool another-https-pool
    }
}

もし、複数のVirtualServer があって、個別にirule 作るのが面倒な場合、
TLS 1.1以下のときに振るpool の命名規則さえ揃えておけば

when CLIENTSSL_HANDSHAKE {
    if { ( [SSL::cipher version] equals "TLSv1" ) or ( [SSL::cipher version] equals "TLSv1.1" ) } {
        pool [LB::server pool]-oldtls
    }
}

みたいにすれば、

のようにpool作れば、irule使い回しできそう。

ちなみにpoolが存在しない場合、clientからの接続は切断されて、/var/log/ltm にログが出る。

TCL error: /Common/tls_version_routing_test <CLIENTSSL_HANDSHAKE> - no such pool: /Common/example.com-https-oldtls (line 1)     invoked from within "pool [LB::server pool]-oldtls"

Mackerel Meetup #12 に登壇してきました

mackerel.io

8/2 に実施されたイベントに行ってきました。
会場: 目黒 アルコタワー ドリコムさんのセミナースペース

現職はマネージドホスティングを提供している会社で、
Mackerel としてはあまりなかった使い方ということで声をかけていただき、発表してきました。
監視システムに課題があったところをMackerel で解決したよ、というお話。

普段会えない開発チーム、CRE の方々と会えて良かったです。
当日はガチガチに緊張してて直前のセッションの内容あまり覚えてないので今復習してます(^p^)

資料

当日 reveal.js で作ったgithub pages にあげてしゃべってましたが、簡単埋め込みできるspeakerdeck にupしなおしました。内容は同じです。


おまけ

発表者特典でmkr Tシャツ貰えました!

FileShare - google cloud platform のNFS Server


Google Cloudのfull-managed NFS Server。AWS でいうEFSですね。

NFSに頼りすぎる異なるサーバ間で接続しすぎると密結合になってしまって、複雑になりかねないところもあるし、App Engine とかのいわゆるサーバレスな構成にできればこういうところも考慮しなくて良くかもしれないけど。

そうは入っても従来のいわゆる単なるインスタンスを冗長構成で使いたい場合もあって、web/app インスタンス間でお手軽に同期が取れるのはやはり便利。


aws はtokyo リージョンにそのうち来る〜と発表があってから随分待った気がする。(数年?)
awsで出たからgcpも来るかなとは思ってたけど予想以上に早く来た。
(とはいえまだbetaだけど)


gcloud shell 叩いてみたらalpha で出来た。

準備

Cloud Filestore API を有効にする
(事前に作成しなくてもgcloud コマンド実行時にも有効にできる)

作成

↑のgcloud のsample の通りでは動かなかったので
gcloud betaをgcloud alphaに、--volumeを--file-share に変更して実行
あと、asia-northeast1 では作成できなかったのでus-centralでやってみた。

ちなみに作業(mount)しているvmはasia-northeast1-c
gcpawsと違って、projectの同じnetwork内であれば(共有VPCを使えば他のprojectも)
(レイテンシはもちろんあるけど) regionを超えてアクセスできる。

reserved-ip-range は指定しなかったらnetworkで使われてないsubnet から適当に作成される?

$ gcloud alpha filestore instances create testnfs-server \
  --location=asia-northeast1-c --network=name="default",reserved-ip-range="10.0.0.0/29" \
  --file-share=capacity=1TB,name=vol1 --tier=STANDARD
ERROR: (gcloud.alpha.filestore.instances.create) PERMISSION_DENIED: Location asia-northeast1-c is not found or access is unauthorized.
$ gcloud alpha filestore instances create testnfs-server \
  --location=asia-northeast1-c --network=name="default",reserved-ip-range="10.0.0.0/29" \
  --file-share=capacity=1TB,name=vol1 --tier=STANDARD

確認

icmpはfilterされてるのかな。
pingが通らなかったのでおや?と思ったけどtcp portは応答する。

$ gcloud alpha filestore instances list
INSTANCE_NAME   LOCATION       TIER      CAPACITY_GB  VOLUME_NAME  IP_ADDRESS  STATE  CREATE_TIME
testnfs-server  us-central1-c  STANDARD  1024         vol1         10.0.0.2    READY  2018-06-27T07:06:28
$ ping -c 3 10.0.0.2 
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.

--- 10.0.0.2 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2049ms
$ telnet 10.0.0.2 2049
Trying 10.0.0.2...
Connected to 10.0.0.2.
Escape character is '^]'.
^]

telnet> quit
Connection closed.

mount

$ sudo apt-get install -y nfs-common
$ sudo mount -t nfs 10.0.0.2:/vol1 /mnt 
$ df -t nfs
Filesystem      1K-blocks   Used  Available Use% Mounted on
10.0.0.2:/vol1 1055841280 180224 1001957376   1% /mnt

reveal.js とreveal-ckでプレゼン資料作成

最近、パワーポイントからの脱却を目指してます。

パワーポイントにも良いところあるけど、個人的にはあまり凝った資料作成しないし、diff しやすいテキストベースのほうが良いかなと。

reveal.js

色々あるけど、一番簡単なのはhtml 内のdiv class="slides" 内のsectionにmarkdown書く。
sectionタグに1pageごと書くのがめんどくさいので---などを区切りにする方法。

  • --- がページの区切り
  • >>>が補足用などで縦方向のページ区切り (data-separotor-verticalで指定)
<section data-markdown 
       data-separator="^\n---$" 
       data-separator-vertical="^\n>>>$">
    <script type="text/template">
Page 1

---

Page 2-a

>>>

Page 2-b

>>>

Page 2-c

---

Page 3
  </script>
</section>

markdown を別ファイルから読み込む方法もあるけど、その場合はnode.js でlocalにwebserverを起動する必要がある。

reveal-ck

ruby製のブツ。一つのmarkdownファイルを元にreveal.js 用の静的を生成してくれる。
reveal-ck start するとlocalhost に10000番のweb serverが起動して、slides.md を編集すると自動的にreload&静的ファイルを再生性してくれるので、資料作成するときの確認が簡単。

$ gem install reveal-ck
$ echo '# hoge' > slides.md
$ reveal-ck generate
$ reveal-ck start

Github/Gitlab Pages、CIあたりで連携しておけば、slides.md をcommit & push したら公開用のhtmlが自動的に更新される、みたいなこともできるらしい、ええなー。

apache 2.4.7 からProxyPassでunix domain socketを指定できるようになってた

nginx + uwsgi(socket) で動いているブツを、apacheが稼働中のサーバに移そうとしたときに、
socketをtcp port に書き換えないといけないの面倒だなーと思ってたけど、2.4.7 からsocketに対応してた。

Unix Domain Socket (UDS) support added in 2.4.7

でもRHEL/CentOS 7の標準のhttpdは2.4.6なので使えない 😇

apache 2.2 LocationMatch 内ではProxyPassではなくProxyPassMatch (ただし、ProxyPassReverseの制限付き)

2.4は不明。2.2ではProxyPassではダメだった。

Location 内でProxyPassしているURLを増やしたくて、
そのままLocationMatchで正規表現で書いてもProxyしてるところがbackendに渡らなくて困った。

セクションの中で使われた場合は、 最初の引数は省略され、正規表現 から取得されます。

ProxyPassMatch の場合は渡す引数を正規表現でとってこないといけないので
URL /foo/

<Location /foo/>
   ProxyPass http://backend/foo/
</Location>

URL /fooもしくは/bar

<LocationMatch ^/(?:foo|bar)/(.*)>
   ProxyPassMatch http://backend/foo/$1
</Location>

最初のカッコはfooとbarをグループしたいだけで変数はキャプチャしたくないので?: つけている。


これで動作はする。ただしProxyPassReverse の扱いがやっかい。
Locationで使っていた

ProxyPassReverse http://example.com/foo 

をそのままLocationMacthで利用すると、backendでredirectが発生したときに正規表現の文字列のまま返ってきてしまう。

$ curl -I http://example.com/foo/hoge
(抜粋)
Location: http://example.com^/(?:foo|bar)/(.*)/hoge/

これはProxyPassReverseのドキュメントにも書いている

セクション内でも起きますが、 おそらく意図どおりに動きません。
と言うのも、ProxyPassReverse が正規表現をそのまま文字列でパスとして解釈しようとするからです。
もしこのような状況で必要なら、セクションの外で ProxyPassReverse を指定するか、あるいは別の セクション内で指定してください。

ここまでくるとアプリケーションやどのURLでアクセスがきたときにどうしたいかなどによるけど
一つのProxyPassReverse ではたぶん綺麗に解決できないので、
ProxyPassReverseが必要な状況なら素直にLocation を個別に書いた方が良いかな。