どこまで仕事を詰めてから人に確認してもらうか【雑記】

これは何

雑記です。
エンジニアとして仕事を可能な限り効率よく進めるために、仕事をどこまで仕上げてから他の人に最終確認してもらうか、という点について考える。 「チームとして」仕事を効率的に進めること、「個人として」効率的に進めることの二つの視点で見る。

目次

背景

年末になり、諸々の仕事がたくさん降ってきた。締め切りが近い仕事が多い。 私は仕事を進めるにあたり、もともとできるだけ深く調べてやっていきたいタイプ。仕事は遅いが硬い仕事を好む。

何を優先しよう

チームとして効率的に進めること

エンジニア一人が仕事を進めることではなくて技術的興味からその仕事には不必要なまで技術調査をすると仕事は滞る。逆に難しいことは置いておいて、これで問題なく動くというところまでならそこまで労力はかからない。
例えば、プロダクトのappleのATS対応のために自サービスを全てhttps化したいシチュエーションがあるとする。ここでは詳しく述べないがATSの要件として必須となるCipher Suiteがある。インフラエンジニアが最低限仕事を進めるのに必要な知識としてはiOSクライアントがしゃべれるcipher suiteは何か、LBがしゃべれるcipher suiteは何か、という視点だけを持って”文字列”(例えば「ECDHE-RSA-AES256-SHA はクライアント、LBも両方とも使えるからOKだな」などと)の対応を見れば良いだけ。負荷については既に設定したものがどれくらい使っているかを見て、アクセス数で比を取れば大まかな値は見積もれる。
しかし、調べていくと例えば以下のような疑問が出てくる

  • Cipher Suiteってなんだ? 鍵交換の部分が楕円曲線暗号(ECDHE)を使えばRSAを使ったものと比べるとCPU処理が重くなるようだが、どういうアルゴリズムの違いがあるんだ? 比ではなくてLBのカタログ性能と見比べて数値的に見積もりできないの?とか。
  • LBのSSLをハードウェアで解く方法って裏で何やってるんだ? 

これらを深いレベルまで調べるのは大変に骨である。実際、今回限られた時間の中では本当にさわりしか学ぶことができなさそうだ。

さて、チームとして短期的に成果を上げるためには、上記のように概要を調べて => 大体こうだろうと文章を書いて => 詳しい人に聞いて大体OKを貰って => 上長の承認を得る(場合によっては情報不足によるやり直し) みたいな流れになる。
本当は次のようなプロセスを踏みたい(が、無限に時間がかかる) 概要を調べる => 疑問を満足するまで潰す => 詳しい人に聞いて裏取りして => 上長も一発承認。

前者のフローではその案件について詳しい人と上長には少し負荷はかかるが確認作業なので大きくない。私の作業量は小さいのでチームとしては割と小さな作業量で仕事を進めることができる。
後者のフローでは私個人の作業量は多いが、確認者の負担は小さい。しかしながら8割から10割に完成度を高めていく作業は0から8割にあげるのの5倍はかかる。

なので、チームとしては7〜8割の完成度の仕事まで自分で仕上げ、あとはうまく流していくという作戦がうまく行く。

個人として長期目線で見ると

上記のように、チーム目線で短期効率を求めて仕事を流していると絶対に自分は「詳しい人」にはなれない。 短期的には今ある仕事を回せばいいが、長期的に見れば会社としてもそれぞれがスキルアップした方が冗長化はできる。個人としても美味しい。裏の技術を知っているエンジニアは貴重だが、上辺だけなぞって仕事をそこそこ流せるエンジニアは割と沢山いる。 そうなると10割の完成度を目指し(実際には8〜9割の完成度だったとしても)満足いくまで裏の理解をした方が良い。とはいえ、あまりにも業務が進まないとお給金は上がらない。難しい。

まとめ

結局のところバランスを取るしかない。締め切りに追われている時には技術調査を少なめにして実験的手法が増えるのはしょうがない。時間があれば論理から攻めて深くまで理解して仕事をする。

追記

めっちゃのんびり働きつつ、満足いくまで勉強しつつ、お給金も沢山もらいたいなあ、という話でした。家で無限に勉強時間をとることでこの問題を解決しているエンジニアもいるが、それは人生の浪費では、と個人的には思っている。人は仕事だけをするためだけに生きているわけではない。業務時間中には全力を出し、プライベートは可能なかぎり仕事から離れて楽しむのが良い。

kibanaで認証かけたいんだけど(nginxによるbasic認証)

背景

kibanaは認証もなくがら空きである。fluentで本番サーバのログをelasticsearchへ流してそれをkibanaでみる。本番のデータでいろいろ表に出ちゃいけない情報もあるので、社内であってもカジュアルすぎる感じで見られると嫌。 そういう訳でkibanaにnginx経由でアクセスを強制することでbasic認証を挟む。

やったこと

  • nginxインストール
  • nginx設定
  • パスワードファイルの配置
  • kibana設定

nginxインストール

詳しく書きません。tar ballからver 1.9のものをインストール。

nginx config

メインの設定は他のサーバと共通。なんでもいい。vhostに以下のような設定。ansibleで書いたやつ。

# basic authentification for kibana
upstream kibana {
    server localhost:5601;
}

server {
    listen       80;
{% if ENVIRONMENT == "production" %}
    server_name  kibana.o-in.hoge.jp
{% else %}
    server_name  kibana.dev.o-in.hoge.jp
{% endif %}
    charset utf-8;

    # allow ip
    include /usr/local/nginx/conf/common-ip.conf;
    deny all;

    error_log /var/log/nginx/nginx_kibana.error.log warn;
    access_log  /var/log/nginx/nginx_kibana.access.log  mylog;

    proxy_buffering off;
    
    # basic auth 
    auth_basic "Enter your ID and password." ;
    auth_basic_user_file "/usr/local/nginx/.htpasswd" ; 

    location / {
        proxy_pass http://kibana;
    }
}

パスワードファイルの配置

nginx 設定ファイルで .htpasswdを読み込んでいる。 apache付属のhtpasswd コマンドを用いる。今構築中のサーバにapache居なくてもOK。他のサーバで作ってコピペしてくればいい。

$ /usr/local/apache2/bin/htpasswd -c ./kibana_pass myloginid
New password:
Re-type new password:

作成したファイルは nginxユーザの持ち物で0600にでもしておく。他のユーザによって書き換えられても嫌だし、ハッシュ化されているとはいえ見られても嫌。

kibana設定

localhostのnginxからのみアクセスできるようにする。 kibanaのhomeディレクトリの下にconfig/kibana.ymlとかがあるので、

server.host: localhost

みたいな記述を入れる。そうするとlocalhostからのみのアクセスを受け付ける。

忘れずに

nginx. kibanaのrestartをして設定を反映する。

コメント

basic認証を初めて使ったけどそんなに難しくない。認証の経路を作って、直接のアクセス経路を断つのを忘れないようにするのが重要だと思った。

BIOSがバージョンアップできているか確認したい dmidecode コマンド

背景

サーバのfirmware のバージョンアップをやった。バージョンアップツールにBIOSのバージョンアップも同梱されているっぽい。実際にバージョンが上がっていることを確認した。導入が2011年ごとのサーバだったので2015年とか2016年に上がっていればOK。 (どのベンダーの物理サーバかはぼかして書いてます)

コマンド

dmidecode コマンドを使う。 このコマンドはハードウェア情報を取得するためのコマンド。BIOSの情報ものってる。

コマンド実行結果

$ sudo dmidecode | grep -A 3 "BIOS Information"
BIOS Information
        Vendor: HP
        Version: P68
        Release Date: 08/16/2015

OK good

コマンドがないんだけど? を解決するwhereis コマンド

背景

CentOS 5系のサーバとかだとコマンドにいろいろパスが通ってなかったりする。 今までは mlocateパッケージを入れて、locateコマンドで探していたりした。

コマンド

whereis コマンドはコマンドとかのありかを教えてくれる便利コマンド。

どのパッケージに入っているの? という話だが、 以下のようにrpmコマンドでファイルがどのパッケージに含まれるか見れる。

$ rpm -qf `which whereis`
util-linux-2.13-0.47.el5

どうやら util-linuxというやつに入っているらしい。core groupに入っている。

使ってみると

$ whereis ifconfig
ifconfig: /sbin/ifconfig /usr/share/man/man8/ifconfig.8.gz

MySQLで他のサーバからdataディレクトリコピーしてきたけど動かない(innodb_log_file_size設定)【問題と解決】

目次

背景

新たにMySQL Slaveサーバを構築したい。既存のSlaveサーバを一旦とめて、dataディレクトリごとコピーして配置。普段だったらmaster.infoとかも入っているし、すんなり動くが、今回はなんか動かなかった。

エラー

mysqld start時に以下のエラー

Starting MySQL.. ERROR! The server quit without updating PID file (/usr/local/mysql/data/seiga-s01b.pid).

対応

順に問題をつぶしていく。

  • pidファイルが書けないのか? Permissionがないとか? => mysqlユーザになり、touchで該当箇所にファイル作成できる。
  • errログがPermissionが原因ではけないとダメという事例も? => mysqlユーザの持ち物になっててOK
  • errorログをtail -fして起動してみる。error log に以下のエラーが出力されている。
InnoDB: Error: log file /usr/local/mysql/data/ib_logfile0 is of different size 0 268435456 bytes

問題はこれだな。ib_logfileはサイズと個数が設定と一致してないとダメだった。設定では128M, 実体は他のサーバから持ってきたので256Mになっていた。 削除して起動してやると問題なく起動。ib_logfileも新たに作成されている。

おわりに

前にファイル側ではなくて設定変更したときに公式ドキュメントに書いてあった知識が役にたった。 innodb_log_file_size の値を変えるときには、MySQLサーバ停止後にファイルを消して起動するべし、とのこと。

MySQL脆弱性 CVE-2016-6662 について (2016 09 13現在)

これは何

MySQLにリモートでコード実行される可能性のある脆弱性 CVE-2016-6662 が発覚。その概要と対応をまとめる。

目次

  • これは何
  • 目次
  • 資料
  • 対象バージョン
  • ざっくり言うと?
  • 設定ファイルが書き換えられるとなぜ攻撃になる?
  • 今回の脆弱性
    • my.cnfに追記する
    • ファイルが無い状態から作る
  • 対応方針案

資料

CVE-2016-6662  http://legalhackers.com/advisories/MySQL-Exploit-Remote-Root-Code-Execution-Privesc-CVE-2016-6662.html

対象バージョン

2016 09 13日現在の全てのバージョン。 具体的に言うと、現時点での最新のバージョンの以下を含む、それ以前のバージョンに脆弱性が存在。

  • 5.7.15
  • 5.6.33
  • 5.5.52

要するにパッチがまだない。 MySQL cloneの MariaDBとPerconaDBにも影響。

ざっくり言うと?

SQLインジェクションを使って、 my.cnf を上書きできる。 攻撃するには以下の条件が必要

設定ファイルが書き換えられるとなぜ攻撃になる?

mysqld_safeがrootプロセスで起動して、mysqldプロセスがmysqlユーザに落として起動される。mysqld_safeのスクリプト(配置場所によるが、例えば /usr/local/mysql/bin/mysqld_safe)のset_malloc_lib()でshared library がmysqlサーバ起動前に読み込まれて--malloc-lib=LIB へセットされる。 設定ファイルを書き換えられるということは、この変数で読み込む値を my.cnfの [mysqld]か[mysqld_safe]セクションで好きに設定できるということ。そうすると、任意のライブラリ(任意コード)がmysqlサーバ起動時にroot権限でされる(mysqld_safe実行時なので)。 3.23.55以前のバージョンだと

SELECT 'malicious config entry' INTO OUTFILE '/var/lib/mysql/my.cnf'

このコマンドでファイルが作れて、設定ファイルとして読み込むことができる。ファイル作成の例としては /tmp/ 下に作成してみると

$ mysql -uroot -p -e "SELECT 'malicious config entry' INTO OUTFILE '/tmp/my_temp'"
$ ls -ltr /tmp/my_temp
-rw-rw-rw- 1 mysql mysql 23 Sep 13 16:50 /tmp/my_temp
$ cat /tmp/my_temp
malicious config entry

今はこの脆弱性は修正されている。MySQLは 0666 permissionsのファイル(というかotherに書き込み権限がある場合)を設定ファイルとして読み込まないようになっている。具体的には以下のエラーが出て読み込まない。

Warning: World-writable config file '/etc/my.cnf' is ignored

しかし、MySQL logging関数で出力されたファイルは 0660 になっているので、設定ファイルとして読み込むことができる。これが今回の問題 

今回の脆弱性

my.cnfに追記する

仮に my.cnfが以下の様なmysqlユーザの持ち物だった場合(例えば以下のようなパーミッションだった場合)

root@debian:~/# ls -l /etc/my.cnf
-rw-r--r-- 1 mysql mysql 72 Jul 28 17:20 /etc/my.cnf

以下の内容をファイルに追記できる。

mysql> set global general_log_file = '/etc/my.cnf';
mysql> set global general_log = on;
mysql> select '
    '>
    '> ; injected config entry
    '>
    '> [mysqld]
    '> malloc_lib=/tmp/mysql_exploit_lib.so
    '>
    '> [separator]
    '>
    '> ';
mysql> set global general_log = off;

ファイルが無い状態から作る

/etc/ 以下にmy.cnfが無い場合には、/etc/ ディレクトリのパーミッションで縛られる。root かつ 0644 だったばあいには mysqlユーザは作ることができない。 どのようなファイルが作られるか、/tmp/以下で試してみる。この方法で作られたファイルは以下のようなPermissionになる 。

$ ls -ltr /tmp/my_temp.txt
-rw-rw---- 1 mysql mysql 685074 Sep 13 16:33 /tmp/my_temp.txt

しかし、この脆弱性だけでは、my.cnfに loggingの最初の行(version情報など)が入ってしまい、設定ファイルとして機能しない。 さらに他の脆弱性 CVE-2016-6663 (2016 09 13現時点では詳細非公開) を使用すると、(余計な情報を消して?)FILE権限なしに、任意の内容を書き込むことができる。

一次対応策

MySQL 5.5だと以下のような設定ファイルが置ける  参考: http://dev.mysql.com/doc/refman/5.5/en/option-files.html

/etc/my.cnf         Global options
/etc/mysql/my.cnf   Global options
SYSCONFDIR/my.cnf   Global options
$MYSQL_HOME/my.cnf  Server-specific options
defaults-extra-file The file specified with --defaults-extra-file=file_name, if any
~/.my.cnf   User-specific options
  • /etc/my.cnf がmysqlユーザで書き込み権限がないこと(例えば rootで 0644 )を確認する
  • /usr/local/mysql 直下が mysqlユーザの書き込み権限がないこと (例えば以下のようになっていること。mysqlユーザはここにmy.cnfを配置できない)を確認する
$ ls -ltrd /usr/local/mysql/
drwxr-xr-x 13 root mysql 4096 Sep 13 17:27 /usr/local/mysql/
  • ファイルを置く権限がある場合には、 root パーミッションで作った my.cnf をダミーとして置いておく。作成も上書きも出来ないように。
  • /etc/mysql/ ディレクトリが存在しないことを確認する
  • /etc/sysconfig/ が mysql ユーザの権限がないことを確認する
$ ls -ltrd /etc/sysconfig/
drwxr-xr-x. 7 root root 4096 Sep 13 17:17 /etc/sysconfig/
  • extra fileとして /home/simainte/my.cnf がある場合はそれが root 0600 になっていることを確認する
  • /home/mysql/ に root 0600 で my.cnfを配置しておく。または /home/mysql/ を削除する

根本対応

パッチはまだない。mysqld_safe で shared_libraryを読み込まないという手もある。

Vmware ESXi でVMホストのディスクが圧迫されてインスタンスが落ちる問題(原因と対策)

背景

バックアップ用DBを作るために、でかいディスクを持つ物理サーバの上にVmware ESXiをたてた。 DBに他のSlaveからデータをscpしてみたら途中で突然インスタンスが落ちた。起動もスナップショットの操作も出来ない状態。 インスタンスへのディスク割り当ては200G。メモリは8G割り当て。 scpしたファイルは40G程度で、開きVMホストの元の空き容量は30G程度だった。

原因

datastoreを更新してみると空きがほぼ0になっていた。 詳細なファイルを見てみると以下のようなファイルが大きかった。(ホスト名を hostnameとする)

  • hostname.vmdk
  • hostname-49271ad6.vswp
    • 8G。メモリオーバーコミットをする設定だと、物理マシンのメモリと直接マッピングされずにインスタンスのメモリはディスクに書かれる見たい。
  • hostname-000001.vmdk, hostname-000002.vmdk
    • 合計で27G
    • 今回の犯人。スナップショットをとった後にインスタンス内で更新があると、その差分を出すためにredoログ(差分)としてここに書かれる。
  • vmware-1.log
    • 合計で数M。今回の問題とは無関係なので略

対策

  • メモリオーバーコミットをさせない。インスタンスのメモリ設定で「すべてのゲストメモリを予約(すべてロック)」設定を入れる。
  • スナップショットを全部消す。そうするとredoログが吐かれないのでVMホストのディスク圧迫が起こらない。

コメント

スナップショットが取れないのは不便だが、物理マシンと同じだと思えばまあよし。 ある程度構築して本番投入するまではスナップショットを使って、ほとんど変更が無くなったらスナップショットを全部消すなどの運用でカバーできそう。