うまいぼうぶろぐ

linuxとhttpdとperlのメモ

apache 2.4 virtualhost 内で一部の無効な設定が警告されない

概要

こんな設定。
確認したのはRHEL7/CentOS7の標準のhttpd (2.4.6)とsclのhttpd24-httpd (2.4.27)

httpd.conf 抜粋

Loglevel warn
# 他は省略
<VirtualHost *:80>
  DocumentRoot /hoge
  <Location />
    AllowOverRide All
  </Location>

  Alias /foo       /path/to/foo
  Alias /foo/hoge  /path/to/hoge
</VirtualHost>

警告

この設定には3つの警告がある。

  1. DocumentRoot /hoge が存在していない
  2. Locationで使用できないAllowOverRide を設定している
  3. Alias /fooが優先されてAlias /foo/hogeが効かない
configtest
$ apachectl configtest
AH00112: Warning: DocumentRoot [/hoge] does not exist
Syntax OK

DocumentRoot についてしか警告が出ない。

解決した設定内容

試行錯誤した結果、Virtualhost内に任意のLoglevelを設定すると警告が出ることがわかった。

<VirtualHost *:80>
  DocumentRoot /hoge
  ## Loglevel を問題の設定より前に書く
  LogLevel warn

  <Location />
    AllowOverRide All
  </Location>

  Alias /foo       /path/to/foo
  Alias /foo/hoge  /path/to/hoge
</VirtualHost>


httpd.conf 内に既に同じLogLevel warnを設定しているけど、この設定を足すと

$ apachectl configtest
AH00112: Warning: DocumentRoot [/hoge] does not exist
[Wed Sep 05 17:59:45.814156 2018] [core:warn] [pid 9709] AH00114: Useless use of AllowOverride in line 359 of /opt/rh/httpd24/root/etc/httpd/conf/httpd.conf.
[Wed Sep 05 17:59:45.814267 2018] [alias:warn] [pid 9709] AH00671: The Alias directive in /opt/rh/httpd24/root/etc/httpd/conf/httpd.conf at line 363 will probably never match because it overlaps an earlier Alias.
Syntax OK

※ forum とかbug情報等はまだ見てない。

big-ip irule でURL Routingしているときの謎の仕様

謎の仕様というかほぼbugかな。

前提

pool を2つ容易

  • pool
    • pool1 default pool
    • pool2 特定URLを処理するpool
      • /hoge/ or /fuga/ からはじまるURL
    • pool1、pool2 ともにcookie persistence を有効
  • virtual server
    • default pool にはpool1 を適用
    • HTTP Profile を適用

irule

when HTTP_REQUEST {
  if { [HTTP::path] starts_with "/hoge/" } {
    pool pool2
  }
  elseif { [HTTP::path] starts_with "/fuga/" } {
    pool pool2
  }
}

確認した動作

よし、オッケーと思っていた。

謎の挙動

curl では再現せず、ブラウザによるアクセスで発生。
pool2 で処理するURLにアクセスして、同一ブラウザで数秒以内 (3秒ぐらい?) に
pool1 で処理するURLにアクセスすると、なぜかpool2 に振られる。


## 解決
irule に明示的にdefaultのpoolを書いたら発生しなくなった。
これが仕様らしい。

when HTTP_REQUEST {
  if { [HTTP::path] starts_with "/hoge/" } {
    pool pool2
  }
  elseif { [HTTP::path] starts_with "/fuga/" } {
    pool pool2
  }
  else {
    pool pool1
  }
}

apacheのrewriteによるredirectをmod_mruby で置き換えてみた

参考

queryがついているURLを扱う場合mod_aliasのredirectでは処理できないので、
mod_rewriteを使うことになるが、数が多いと辛くなる。
また変更の度にapache再起動が必要となる。

.htaccess が使える場合、再起動は不要だが、
apacheをreverse proxyとして利用している場合(ProxyPass)、.htaccess は使えない。

mod_mruby 使ったら簡単にできないかな?と思って少し調べたメモ。

使いそうなディレクティブ

  • mrubyHandlerMiddle
  • mrubyFixupsMiddle

- ProxyPass で扱うURL部分もredirectなどの処理対象にしたい場合はこれ?

  • mrubyQuickHandlerMiddle

- フックポイント ap_hook_quick_handler
- RewriteRule で処理しているURLもmrubyで上書きしたい場合はこれ?

mrubyQuickHandlerMiddle /var/www/mruby/redirect.rb

/var/www/mruby/redirect.rb

何もしない場合はapacheの次の処理に渡すので
Apache::DECLINED を使う

csvの処理にmodule使ってなくて、エラー処理もしてない簡単なsample

r = Apache::Request.new
s = Apache::Server.new

redirect_csv = '/var/www/mruby/redirect.csv'
hash = {}
File.open(redirect_csv, 'r') do |f| 
  while l = f.gets
    key, value = l.chomp.split(",")
    hash[key] = value
  end
end

key = r.uri
if r.args then
  key = key + '?' + r.args
end

if hash[key] then
  r.headers_out["Location"] = hash[key]
  Apache::return(Apache::HTTP_MOVED_TEMPORARILY)
else
  Apache::return(Apache::DECLINED)
end

redirect.csv

/hoge/,http://example.com/hoge/
/fuga/,http://example.com/fuga/
/hogem?num=10,http://example.com/hogem/?num=10

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シャツ貰えました!

FileStore - 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