2021-12-02

prometheusのrate()関数の罠

 久しぶりのAdventカレンダー挑戦、うまくいく気がしません。

閑話休題。実のところ、rate()関数というよりは、サーバー側のmetric初期化問題です。

さて、何らかのサーバーAがあったとして、それが更に他のサーバーBにRPCを送っているとします。サーバーBの方でホワイトボックスモニタリングをするのは当然として、サーバーA側でもサーバーBからのレスポンスを記録すると思います。というわけで、サーバーAでは以下のようなmetricsを吐くとします。

rpc_response{status=OK, service=B} 100

T0でこの状態だったとします。そしてT1(T0 + 1分)で 

rpc_response{status=OK, service=B} 160

となってた場合、

irate(rpc_response[5m])
=> {status=OK, service=B} 1

となります。そしてT2(T0+1分)でエラー発生、metrics

rpc_response{status=OK, service=B} 190
rpc_response{status=ERR, service=B} 60

となったとしたら

irate(rpc_response[5m])
=> {status=OK, service=B} 0.5

であり、ここにstatus=ERRが出てきません。これはirate()が最低でも2つのデータを必要とするからです。

じゃー、T3でどうなるかと。このエラーは突発的なものだったのでにstatus=ERRは変化がなかったとします。

rpc_response{status=OK, service=B} 250
rpc_response{status=ERR, service=B} 60

はいとりあえずT2、T3の2つのデータがあるのでirate()が計算できるわけですが…

irate(rpc_response[5m])
=> {status=OK, service=B} 0.5
   {status=ERR, service=B} 0

となります。status=ERRの方は値が0です。T2とT3の間では値が変わってないので仕方がないですね。

というわけで、irate() (rate())を使っている限り、このエラーはグラフにも表示されず、アラートも発生することはありません。

この問題の原因は「データ(カウンター)が存在しない != 値が 0」というところにあります。そこで、この問題の解決策は…

  1. もし取りうるstatusが最初から分かっているのなら、事前にrpc_responseカウンターを全てのstatusに対して0で初期化しておく。
  2. あきらめるw
  3. rate()の結果が存在しないけど、その元となるmetricが存在する場合には、その元となるmetricを直接使うようにPromQLをゴリゴリ書く
のいずれかです。番外として「Prometheusに手を入れて『rate()では、データが存在しない == 値が 0とみなす』」というのもありますが、これはprometheusの先祖であるborgmonがすでに通った茨の道、絶対におすすめしません。

なお、計算を簡単にするためにirate()を上では使ってましたが、「0で初期化されてないカウンター」問題はrate()でも一緒です。

ところで、bloggerのエディターはしょぼいですね。中の人も全然使ってないんじゃないのかな…

2021-11-30

SREになったきっかけ

多分、「 SRE」という肩書で仕事をした初めて日本語話者(のうちの一人)なので、そうなった経緯について簡単に。


Googleに2006年に入ったとき、私は Sysops (Linux System Administrator) というポジションでした。当時の Sysopsを含む IS (Internal Systems) チームのトップ (CIO) は DCM (https://en.wikipedia.org/wiki/Douglas_Merrill) という人だったのですが、彼が2008年でGoogleを辞めてCIOが変わりました。ありがちな話ではありますが、トップが変わると一番最初にするのは組織改編ですよね?! ちょうどその頃リーマンショックなんかもあってISチームの大幅な見直しがありました。


で、偉い人たちが Sysops チームの組織構造をチェックしてみたところ、なんかダメダメな感じなので、より洗練されているSREチームに統合しようという話になったとかならなかったのかは定かではありませんが(なんかBen Treynorが東京に来たときに色々話してたけど忘れたw)、気がついたら「sysops は(ほぼ)全員面接なしでSREに職種変更します!」ということになり、日本初のSREが誕生したのでしたw


というわけで「 SREになったきっかけ」の答えは、「自分で望んだのではなく、Gooogleで働いてたら、気がついたらSREになってた」でしたw

2017-06-20

インフラエンジニアのスキルチェック

どっかのサイバーメガネさんがネタ提供してくれたので。ネタの妥当性には触れません。

DB設計

既にあるのからER図を作成せざるをえない状況に追い込まれたというか、そういう状況だから呼ばれたことはあるけど、実は一からやったことない。

  • 要件からDB定義を作成できる
    「やったことない」けど、なんとかなりそう
  • ER図を作成できる
    「やったことはある」けど、ツールをぽこぽこいじっただけだよ
  • 第3正規化まで正規化できる
    「やったことない」けど、まーできるんじゃないかな
  • パフォーマンスを意識したインデックス設定ができる
    「したことない」。いきなりは多分無理。

パッケージ管理

最後に外に出したのはなんだったか、記憶にないぐらいには素人です。

  • RPMビルド環境がつくれる
    「質問の意味が分かりません」。ビルド環境って、RH なりで開発関係のパッケージをインストールするだけじゃないの??? クロスコンパイルみたいに、ビルドのために target 用の環境とか用意しないといけないの?
  • specファイルが書ける
    昔はちょこっと書いてたけど10年弱触ってないので、「ちょっと書けます」ぐらいで。
  • 独自YUMレポジトリを構築できる
    「やったことない」けど、どっかにマニュアルでもあればできると思う。
  • debパッケージも作成できる
    いちおうしたことはあるので「ちょっとできます」ぐらいで。

Webサーバー構築


ここ10年、社内のプロプライエタリなコードしか触ってないので…

  • Apache・NginxでWebサーバーを構築できる
    「Apacheならやったことはある」。Nginx とか触ったことないよ
  • リバースプロキシを設定できる
    「やったことない」と思う。
  • エラーログが読める
    「分からない」。アクセスログなら読めるけど、Apacheとかのエラーログとか見た記憶がない
  • バーチャルホストが設定できる
    「やったことはある」ぐらいかな。
  • Rewriteのルールが記述できる
    「やったことない」。いや、あるかも。忘れた。
  • HTTPSのWebサーバーを立てられる
    「やったことない」と思う。色々なんやかやで SNI とか SAN とか頭を悩ませたことはあるけど、webサーバーを立てたことはない気がする。
  • HTTP/2化できる
    「やったことない」。
  • 負荷分散計画が立てられる
    「できない」。なんかもう GSLB に慣れすぎて、超巨大インフラが勝手に色々してくれる環境にどっぷりつかっててやばいです。

DBサーバー構築

DBサーバーとかいじったことないのでパス。全部出来ない。

DNSサーバー構築

DNSサーバーも、ここ10年社内のプロプライエタリなやつか触ってない。

  • DNSの仕組みを理解している
    「ちょっとだけ」なら理解している。なんか色々難しいことは分かりません。
  • BINDでDNSサーバーを構築できる
    「やったことはある」程度かな。やっぱりここ10年ぐらいいじってないし。
  • ゾーンファイルを記述できる
    「やったことはある」。
  • DNSスレーブサーバーを構築できる
    「やったことはある」
  • 浸透と言わない
    「浸透とは言わないけど、propagation とは言う」。誰に向かって話すかにもよるけど。

メールサーバー構築

メールサーバーも、ここ10年(以下略

  • Postfix / qmailで送信メールサーバーが構築できる
    「Postfixもqmailも構築したことはある」。
  • Dovecotで受信メールサーバーが構築できる
    「やったことない」。
  • メールサーバーのエラーログが読める
    「多分読める」。ログがどんな感じだったかさっぱり思い出せないけど。
  • バーチャルエイリアスが設定できる
    「ナニソレ?」。Postfix で複数ドメイン運用する設定だったっけ?まじ忘れた。
  • POP before SMTPが設定できる
    「やったことない」。まじやったことないよ。
  • IMAPが設定できる
    「やったことはある」。でも完全に忘れた。昔は自社サーバを Courier IMAP で構築した記憶がある。
  • SSL証明書を用いてPOP3 / IMAPSが設定できる
    「忘れた」。なんかそういう設定を試したことはあると思う。
  • スパムメールに対応できる
    「ものによる」。スパムも大量に来たら無理じゃね?SpamAssassinなら少し触ったことがある。

キャッシュサーバー

キャッシュサーバーも社内のプロプライエタリなやつしか触ったことないよ。パス。

ロードバランサー

ロードバンサーも社内のプロプライエタリなやつしか触ったことないよ。パス。

監視サーバー

監視サーバーも(以下略

ログ管理

ロ(以下略

AWS

個人的に、他社サービスを使って勉強しなきゃいけないとは思ってるんですけどね…💦

仮想化

ganetiを使ったことは少しあるけど、Xenとかよく分かりません。

  • XenやKVMを使った仮想化環境を構築できる
    「やったことない」。ganetiならある。
  • OpenStackを使った仮想化環境を構築して運用できる
    「やったことない」。
  • NovaやNeutronなどのコンポーネントの特性を理解している
    「ナニソレ?」
  • VMware vSphereを使って仮想化環境を構築して運用できる
    「やったことない」

Docker

コンテナとか、プロプライエタリな(以下略

ストレージ

ここも、かれこれ10年ぐらいいじってないし…

  • CUIでパーティション操作ができる
    「やったことある」
  • 各ファイルシステムの特性を理解している
    「分かりません」
  • 誤って削除したファイルの救出方法を知っている
    「ほとんど分かりません」。lost+foundにあるファイルがあればラッキーだけど。それ以上は無理。
  • 容量が肥大化しているファイルを特定できる
    「できることもある」。とりあえずできない場合が思い浮かばないけど、そんなこともあるでしょう。
  • ディスクI/Oを計測しボトルネックを特定できる
    「ディスクI/Oの計測はできるけど、それだけでボトルネックを特定できる気がしません」。
  • ファイルマスクを理解している
    umaskのことであれば「だいたい知っている」かな。
  • ファイルのタイムスタンプを変更できる
    「だいたいできる」。色々なファイルシステムがあるので、タイムスタンプが変更できない場合もあるし、そもそもタイムスタンプが固定値とかいうファイルシステムもあったりしますし。
  • RAID0〜RAID10までのRAID構成が組める
    「無理」。RAID 2, 3 は対応する機器もコードも見たことない。頑張ればソフトウェア実装できないこともないかもしれないけど、そんなんで信頼性が得られるとは思えません。
  • ソフトウェアRAIDとハードウェアRAIDの特性の違いを理解している
    「少しは知ってます」が、理解しているかというと自信ないです💦
  • NFS環境が構築できる
    「やったことある」。最後に構築したの、20年前ぐらいかも。
  • Samba環境を構築できる
    「やったことある」。これも最後に構築したの、20年前ぐらいかも。
  • lsyncdを使ってファイル同期環境が構築できる
    「やったことない」。ってゆーかナニソレ?
  • テープドライブのCUI操作ができる
    「やったことはある」。あれはLTOだったかDLTだったか…やっぱり17-8年前かな。

途中で疲れたのでこの辺で。気が向けばそのうち続きを…

2016-06-09

XKB で遊んでみよう (2)

xkb_keymap

xkb_keymap エントリーは、xkb で使われる設定一式です。中身は
  • xkb_keycodes
  • xkb_types
  • xkb_compat
  • xkb_symbols
の各エントリーからなります。おまけとして
  • xkb_geometry
というエントリーも存在しますが、単に各種設定ツールでキーボードの絵を表示するのに必要な情報が入ってるだけなので、キーマップをいじるという観点ではガン無視でオッケーです。

xkb_keycodes

デバイスから受け取ったスキャンコードに抽象的な名前、シンボル名を与えるための設定です。他のところの設定において、スキャンコードではなくここで設定されたシンボル名を使うことで、「Ctrl と Caps を入れ替える場合、US キーボードではスキャンコード 11 を Caps に、JP106キーボードの場合はスキャンコード 22 を Capsに」といった、キーボードとオプション設定の組み合わせ全てでスキャンコードを列挙する必要がなくなります。

ただし、抽象化の目的によって大きく分けて2種類のシンボル名が用意されています。一つは物理的な位置に基づくものです。最下段のキーは左から順に <AA00>, <AA01>, ... (ただし、最下段は特殊キーしかないのが普通なので、<AA00> 以外が使われることは稀)、下から2段目は <AB00> (左Shiftキーの位置), <AB01>, ... となっていきます。

もう一つは機能に基づくもので、<HKTG> (Hiragana-Katakana ToGgle) や <TLDE> (tilde) みたいなものがあります。ただし、あくまでもスキャンコードにシンボル名を与えるだけなので、<TLDE> が実際に ~ である必要はありません。というか、わざとややこしい例を出したのですが、<TLDE> は手前から5段目の右端のキー(US キーボードなら ~ キーがある位置)という、位置にあるキーのためのくシンボル名です。ややこしい。そういう意味であれば、単純に <AE00> にしとけと思うんですけどね。

日本語キーボードは、1 の隣は「半角/全角キー」なので、実際の設定ファイルからその当たりを抜き出すと
<TLDE> =  49;
alias <AE00> = <TLDE>;      // Some geometries use AE00
alias <HZTG> = <TLDE>;      // Hankaku_Zenkaku toggle
と書いてあると思います。

もう眠いので、続きはまた明日(以降のいつか)です。

2016-06-08

XKB で遊んでみよう (1)

元ネタは私の G+ポスト です。

Emacs を使ってるとどうしても小指が痛い。解決方法として

  1. Emacsを使わない
  2. 指の付け根でCtrlキーを押す
  3. フットペダルを使う
などが挙げられますが、
  1. Emacs以外は考えられない体にされてしまっている。
  2. 試してみてはいるけれど、ちょっとまだ慣れない
  3. あまり一般的でないハードウェアには依存したくない
などの理由により、X11 上でキーマップをゴニョゴニョしてなんとかしのげないかと考えるに至りました。

で、X11 上でキーマップをゴニョゴニョするといえば大昔は xmodmap 一択だったのですが、近年では XKB を使うのが一般的ではないかと思います。Fedora でモニョモニョしてた頃、とりあえずあら探しした記憶があるのですが、さすがに10年も触らないと忘れてしまいます。あと、個人的に X11 と djb の書いたコードは読まないことにしているので、こんなん書いている割に理解は浅いです。

XKB 使ってユーザーがキーマップをいじる場合、基本的に使うのは xkbcomp コマンドです。setxkbmap は xkbcomp の簡易ラッパーコマンドという認識でいいと思います。

setxkbmap, xkbcomp などで色々と検索すると何やら出てきますが、とりあえず「無変換」キーを Control キーとして (US キーボードで) 使うには

xkb_keymap {
        xkb_keycodes  { include "evdev+aliases(qwerty)" };
        xkb_types     { include "complete"      };
        xkb_compat    { include "complete"      };
        xkb_symbols   {
                include "pc+us+inet(evdev)"
                key <MUHE> { [Control_L] };
                modifier_map Control { 
<MUHE> };
        };
        xkb_geometry  { include "pc(pc105)"     };
};

こんな感じのファイルを用意して xkbcomp FILE $DISPLAY 2>/dev/null を実行すれば OK です。setxkbmap -print で得られた結果に太字の部分を足しただけです。

この設定ファイルに複数設定を加えるて xkbcomp -m でそれを切り替えることにより、色んな設定を試せるのですが、細かいこと書くのは面倒になってきたので、次に続く(かどうか分かりません)

2016-02-17

glibc getaddrinfo() 問題 (CVE-2015-7547) について

さて、いつも同じですが、今回もあくまでも個人としての投稿です。会社としては CVE-2015-7547: glibc getaddrinfo stack-based buffer overflow 読んでということで。

脆弱性の内容、各ディストリビューションからのアップデートは各テック系サイトのニュースをご参照ください。

さて、大人の事情によりすぐに直せないよーという場合の緩和策(あくまでも緩和策です)として [PATCH] CVE-2015-7547 --- glibc getaddrinfo() stack-based buffer overflow では以下のものが挙げられてます:

UDP

  1. 513 バイト以上の UDP DNS パケットを firewall で落とす
  2. (略)
  3.  `options edns0` を /etc/resolv.conf で使わない。EDNS0 は 512 バイトより大きいレスポンスを許可するので、正当な DNS レスポンスでも overflow を発生させることが出来てしまいます
  4. (略)
元のメールの想定読者がシステム管理者ではないので、クライアントコードでの mitigation は省略しました。

TCP

  1. DNS リプライを 1024 バイトまでに制限する
これはちょっと理由が分からなかった。なんでこれでいけるん?fragment が発生しない最小値 (MTU の最小値) は IPv4 なら 576 バイト、IPv6 なら 1280 バイト。DNS/TCP パケットを再構成した上で処理する firewall なら、2048 バイトじゃね?

read() のバッファサイズと発行回数の都合で、1 packet が 1024 バイトまでならバッファがあふれる前に処理できる可能性が高い? でも、「パケット」については言及されてない。


ちゃんと読んでから後で訂正するかもですが、単に A と AAAA の合計で 2048 バイト超えないようにしろってことだと思う。

有効でない緩和策


ちなみに、意味のない緩和策として

  1. `options single-request` は内部でのバッファー管理方法に変わりはないので意味なし。
  2. `options single-request-reopen` も 1. と同様。
  3. IPv6 を無効にしても、(AF_UNSPEC が使われていると)AAAA クエリを投げること自体は止められない。
    • だから `sysctl -w net.ipv6.conf.all.disable_ipv6=1` は意味ない
  4. ローカル、または中間のリゾルバで IPv6 をブロックしてもダメ。クエリを並行して投げるところがバッファ管理の問題を引き起こしてるからです。exploit パケット自体は A への応答でも AAAA への応答でもありえる。
が挙げられてます。

その他

不正でない DNS レスポンスで exploit 可能だし、多分中間に cache サーバーがあってもその先まで侵入可能っぽいよ
ってことも書いてあるんで、単にDNSリレー/キャッシュを守るだけじゃクライアントを守れないっぽい (dnsmasq ならレスポンスサイズを制限できる)。

2014-09-25

Bash の脆弱性について

CVE-2014-6271 の件について、何かわかってない記事が散見されるので簡単にまとめ。

問題点

環境変数が特殊な文字列の場合、Bash はそれを関数定義とみなす(この仕様がそもそもどうなのよ、と思う人は/bin/shをbashにするのはもうやめましょう)。そのロジックに誤りがあり、関数定義でない部分も読み込み、その部分が実行されてしまう。

影響範囲

/bin/sh が bash でないシステムの場合

明示的に bash スクリプトとして起動されたスクリプトだけが影響を受ける。ただし SSH サーバーの場合、ユーザープログラムを実行する場合にユーザーのシェルを使用するので、そこで影響を受けることがある。

/bin/sh が bash であるシステムの場合

system(3) や popen(3) が内部で /bin/sh を利用しているので、影響は広範に渡る。

CGI


特に話題になってるのが CGI である。CGIは仕様 (RFC3875) により、外部から受け取った情報を環境変数に入れた上で (section 4.1.18 参照) 外部コマンドを実行することになっている。ウェブサーバーの実装によるが、このとき system(3) (またはそれに類する) を使って外部コマンドを実行していれば今回の脆弱性の影響を受ける(が、普通は system(3) は使わないし、少なくともapacheはそんなことしない)。

また、環境変数は明示的に制限しない限り子供のプロセスにも引き継がれるので、ウェブサーバーが system(3) を使っていなくても、そこから起動されたプログラムがさらに外部コマンドを system(3) 相当で起動した場合、同じように脆弱性の影響を受ける。

SSH

openssh はサーバー側の AcceptEnv の設定(とクライアント側の SendEnv)によっては手元の環境変数をリモートに送ることができる。環境変数が評価されるのは認証後なので、通常はあまり大きな問題ではないが、サーバー側で ForceCommand で特定のコマンドしか実行しないようにしていた場合、それをバイパスすることができる。なお、ForceCommand はそのユーザーのシェルで実行されるので、zsh とかにしていると影響を受けない。

<追記>
bugレポートちゃんと読んでなかった。もしかしたら AcceptEnv に関係なく TERM は送られるかも。それと、ForceCommand の場合、クライアント側の引数が SSH_ORIGINAL_COMMAND 環境変数にセットされるので、ssh remote_host "() { :;}; ..." とかするだけでいけるっぽい。
</追記>

なおほとんどの人には関係ないとは思うが、クライアント側で ProxyCommand でモニョモニョしている場合、ProxyCommand は実行ユーザーのシェルで解釈される (/bin/shではない) ので、もし ProxyCommand にもクライアントの環境変数が渡る場合(まだチェックしてないので、誰かチェックしてよー)は、リモートを攻撃しようとしてたら何故か自分を攻撃してたということもなきにしもあらずなので、そんな人は注意が必要である。

<おまけ>
ForceCommand とか ProxyCommand が /bin/sh を使わないのは、多分、ユーザーのシェルを制限付きシェル (rsh, rbash) にしてセキュリティを強化たい場合用のはず。
</おまけ>

dhclient

DHCPクライアントの実装の一つである dhclient は、システム管理者によって簡単にカスタマイズできるように、受け取った情報を環境変数に入れた上で各種スクリプトを起動する仕組みになっている。偽の、というか勝手に DHCP サーバーを立てるのは簡単なので、偽DHCPサーバーから偽装された応答を返すことで、DHCPクライアントが動いているホストを乗っ取ることができる。DHCPクライアントは root 権限で動くので深刻な問題になりうる。

CUPS
よく知らん。バグレポートに影響受けるよって書いてあった。

prometheusのrate()関数の罠

 久しぶりのAdventカレンダー挑戦、うまくいく気がしません。 閑話休題。実のところ、rate()関数というよりは、サーバー側のmetric初期化問題です。 さて、何らかのサーバーAがあったとして、それが更に他のサーバーBにRPCを送っているとします。サーバーBの方でホワイトボ...