2018年10月21日日曜日

とあるインフラエンジニアの仕事に対する考え方

インフラエンジニア(小中規模の構築~運用)の仕事における考え方について整理してみました。使っているプロダクトや実例は書けないのですが、2016年度から4~5人を束ねる役目をしているので、思っていることをつらつらと。他にも書き漏らしたことがあれば追記します。

  • 仕組みをデザインせよ
    1. 人はミスをする生き物である。ミスをしたらなるべく繰り返されないよう仕組みから改善せよ。
    2. 事業が半永久的に継続できるよう、緩やかにでも変化に耐えられるよう、中で人が育つような仕組みを作れ。
    3. 若いうちはn年目にはn年目の業務が当たる仕組みにせよ。よほどの天才でない限り手順を踏まずに先に進むのは難しい。
    4. 若い連中には自分で走れる(=不明な点は調べものをして適切な結論を出せるようになる)だけの時間を最初に与えられるのがベストである。
    5. 予算が取れるなら全体に好影響が出るもの、サービス利用者と管理者の双方が喜べるようなことに金を突っ込んで改善していけ。
  • いかに楽にオペレーションするかを念頭におけ
    1. 業務を楽に回すために工夫をせよ。シンプルに作ることで同僚への業務の引継はスムーズになる。
    2. 総コストが下がるように工夫せよ。サービス利用者や対外折衝といったコミュニケーションに関わるコストや、運用の手間を減らすことによる人件費の削減を考慮せよ。
    3. 普段から楽になるように作ることで、次の方針を考える時間を作ることができる。楽な環境ではさほど伸びないが、楽になるように考える過程で実力は伸びる。
  • 知識をアップデートし続けよ
    1. 仕事のコミュニケーションがうまくなるためには技術的な会話について行ける必要がある。新卒同然のままで話ができる訳ではない。
    2. 学習は若いうちにやっておくと費用対効果が高い。未経験でIT業界に入るなら、まずは体系だった知識をつけるために基本情報技術者試験を受けて基礎を叩き込め。そして遅くとも20代のうちに応用情報まで受かっておけ。うっかり何も知らないまま年功序列で上司になって、指示も出せないという状態になると致命的に不味い。
    3. 知識を増やすことは、日々のオペレーション手法に幅がでること(=複数の方法を提案できる)や前任の担当者よりもベターな方法を提案できることにも繋がる。
  • 勤勉な無能は銃殺刑にせよ
    1. 真面目な(=勤勉な)奴が間違った(=無能な)判断で仕事をすすめると取り返すためのコストが高くつく。勤勉な無能と判断されてしまうと、影響範囲が小さいある程度ミスしても許される仕事しか与えられなくなる。
    2. 元ネタはゼークトの組織論による軍事ジョーク。人は{有能、無能} × {勤勉、怠惰}の4パターンに分類されるとされる。
    3. 自身が目指すところはゼークトの組織論で司令官タイプの「有能な怠惰」である。楽に回せるために頭を使う。英語では "Think hard, work lazy." といったところである。
    4. どうしても勤勉な無能を使わざるを得ないのであれば、作業の相当前から計画を立てさせて、当日の作業はオペレータとして手順書通りにやれば十分というところまで持っていく必要がある。
  • 完全年功序列と完全実力主義はどちらもダメなので混ぜるようにせよ
    1. 年功序列のメリットは、頑張っても昇給が一定なので若手を教育することで業務負担を減らそうとするインセンティブが働くことである。完全実力主義は下を教えないことで差をつけるインセンティブが働きやすい。
    2. 年功序列のデメリットは、能力不足のミスマッチや勉強無しでも周囲と同じだけ昇給するため、平均以上のパフォーマンスが出るメンバーからの納得感が得られにくいことである。
  • 採用
    1. 採用する側、される側、双方不幸にならないように歩み寄れ。
    2. 外に見える成果物や公開しているアカウントがあれば、そこで程度を明らかにせよ。極端なハッタリかまして入ると不幸になる可能性が高くなる。

2015年6月10日水曜日

SMTP-AUTHとデータベースのパスワード暗号化の関係

今回はメールサーバを構築するときの認証に関わるお話。ネットでの情報を中心にしつつも個人的な言葉でメモとしてまとめてみました。ラベルはCentOSとしておりますが、Linuxにおける一般的な話となります。理解が間違ってる可能性もゼロではないので、その辺は話半分に読んで頂きたいと思います。

メールサーバを構築する際の仕様は次の条件を仮定します。

  • メール利用者の情報(ユーザ名、パスワード)をデータベースにおく
    • バーチャルドメイン(Linuxのサーバにログインするためのアカウントとは関係ないのでバーチャルと言われるらしい)のメールサーバにおいてはよくある状況と思われます
  • メールサーバの不正利用を防ぐため465番ポートでSMTP-AUTHを利用する
    • 注意:587は使わなくてもSMTP-AUTHはできます
  • 25番ポートはSSLでの通信をせず、465番ポートでSSLでの通信を行う

ここで問題になるのは、データベースに置くユーザパスワードをどのように保存するかという点です。安全にメールクライアント(ThunderbirdとかOutlookなど)からメールサーバまで通信するのに、暗号化しない25番ポートを使うのであれば、ユーザやパスワードの対を送信する際には、CRAM-MD5のようなアルゴリズムでハッシュ化アルゴリズムを使うしかありません。しかし、CRAM-MD5は非可逆で、かつ毎回認証のたびに異なる文字列を用いてハッシュ化されたものが送られてくるため、データベースの方でMD5などで復号化できない保存をしていると、送られてきたパスワードと一致しているか調べる方法がありません。そのためデータベース側は平文で保存するということになります。よって上の条件では、25番ポートを使う限り、通信経路でパスワードを安全にするのと引き換えに、データベースのパスワードの安全性が落ちます。

データベースの問題を解決するために、DBでパスワードのハッシュ化を行う場合は、非可逆なハッシュ化されたパスワードを送られても困るので、クライアントとサーバ間は平文でパスワードをやりとりする必要があります。平文で送れば、メールサーバでハッシュ化してデータベースの中身と比較することは容易です。例えばMD5でのハッシュ化は$1$のような始まりのパスワードになっているため、どのようなアルゴリズムでハッシュ化しているかということが分かるようになっているためです(/etc/shadowも同じようなパスワード保存をしている)。この場合、平文で通信すると経路上は当然危険なので、465番ポートでSMTPsを使うことが必須となります。

いずれにせよSMTPsを使えばとりあえずは安心なのですが、どうしても25番ポートしか使えない場合があるときは、DBは平文でパスワードを保存をすることになりそうです。

2015年2月2日月曜日

絶対に描いてはいけないグラフ入りスライド24枚

Japan.R 2014で絶対に描いてはいけないグラフ入りスライド12枚と題して発表してきました。発表時間は5分という制約があったので、あえなく当日のスライドは半分に。本来発表に使いたかったものを含めてスライド数は倍にしての公開です。

2014年11月27日木曜日

Rでオブジェクトの存在を確認する方法

Rでは変数名の上書きをうっかりしないよう、プログラマは変数を意識してコードを書かなければならない。そこで、Rにおいてオブジェクトが既に存在しているか確認する方法についていくつか挙げてみる。

  1. ls()関数
    • オブジェクトの一覧を表示する関数である。search()関数を利用するとサーチパス上にある名前空間の一覧をすべて見ることができる。
      > search()
      [1] ".GlobalEnv"        "package:stats"     "package:graphics" 
      [4] "package:grDevices" "package:utils"     "package:datasets" 
      [7] "package:methods"   "Autoloads"         "package:base" 
      

      単にls()とすると、".GlobalEnv"の中にあるオブジェクト一覧が表示される。

      > a < -5
      > ls()
      [1] "a"
      
      他の名前空間にあるオブジェクト一覧を知りたいというときは、search()関数で分かった順番を基に、pos引数を使って指定すればよい。以下の例では、2番目の値にあったstatsパッケージのオブジェクト一覧を見ていることになる。
      > head(ls(pos=2))
      [1] "acf"        "acf2AR"     "add.scope"  "add1"       "addmargins"
      [6] "aggregate" 
      
  2. exists()関数
    • オブジェクトの存在をダイレクトに確認するのであれば、この関数を利用するとよい。

2014年10月31日金曜日

PHPにおける文字のエスケープ処理

magic_quotes_gpcというオプションがphp.iniにある。このオプションが有効になっていると、データを渡していくことを繰り返すうちに文字列のエスケープの回数が増えるという問題が発生するそうだ(詳しくはこちらを参照)。オプションが有効化されていることで、エスケープされてしまう文字としては5c問題に該当する文字になる。そこで、一般的な処理としてどのようにエスケープ処理のコードを書くのかということについて示しておく。今回はDB(PostgreSQL)に入れるための文字列がフォームから入ってきた場合を想定しておく。

<?php
function convert_str_for_query($string){
  if( get_magic_quotes_gpc() ){ // magic_quotes_gpcオプションの状態を取得
    $string = stripslashes($string); // 全体に対しバックスラッシュを取り除いた文字列を返す
  }
  $string = htmlspecialchars($string); // <や&のような文字列をエスケープする
  // 上のコードは一般的には表示の際に対策を立てておくためと考えられる
  $string = pg_escape_string($string); // PostgreSQLのクエリとなる文字列をエスケープする
  // ちなみにMySQLであれば、$string = mysql_real_escape_string($string); とする
  return $string;
}
?>

2014年10月28日火曜日

PHPmemo_day15

PHPの基本に関するメモ。参考にしているのはPostgreSQL徹底入門の第5章です。

  • header関数を用いることで、charsetを指定することができる。htmlのheadタグ内に書かなくてもよい。またリダイレクト先を指定することもできる。書き方は以下のコード参照。
  • <?php
    header('Content-Type: text/html; charset=UTF-8'); // 文字コードの指定
    header('Location: リダイレクト先のURL'); // リダイレクト先の指定
    ?>
  • pg_query_params関数は文字列を挿入してqueryを実行する関数であるが、自動的にエスケープ処理を行うことができる。これによりSQLインジェクションを回避することができる。
  • PHPにもCやJavaと同じく三項演算子がある。
  • $_REQUESTというスーパーグローバル変数がある。これはphp.iniのvariables_orderの項目でリクエストの内容をマージしたものが含まれている。普通は$_GET、$_POST、$_COOKIEの優先順位となる。リクエストメソッドに関係なく、$_REQUESTから参照すればパラメータの値を受け取ることができる。
  • htmlのコードとしてPHPを入れる場合はinclude関数でファイルを読み込む。同じファイルで何度も読み込む場合があるのでinclude_once関数自体はあるが一般的ではない(何度も読み込むミスを防ぐ場合に使う)。関数を読み込みたい場合はrequire_once関数を使うという棲み分けがある。
  • 最近のwebシステムにおけるユーザ登録ではメールを仮登録し、仮登録した先のメールアドレスに本登録用のURLを送ることでメールアドレスが正しいものであるか検証することが多い。メールアドレスの形式が妥当なものであるか判断するのは厳しくしすぎないようにしておく(厳密にRFCに従っているか調べるということまではしないということ)。
  • パスワードを単純にsha1関数で暗号化したものを保存しておくのは、レインボーテーブル(暗号化前の文字列と暗号化後の文字列がペアになったテーブル)により、容易にパスワードが破られる可能性があるためよくない。そこで、ソルトと呼ばれる、ランダムな文字列を適当につけてから暗号化することにより、レインボーテーブルによるパスワード対策を行うことができる。
  • require関数はリダイレクトすることになるが、このときリダイレクト先はURLではなく相対パスにしなければならない。ファイルの位置関係で指定の仕方が変わってくることに注意。
  • HTTPの仕様として、データは文字列でやりとりされるので、0という値がブラウザから渡されるとそれは数値ではなく文字列となっている。ただしPHPでは配列の添字の数字は数値として扱われる。以下の例では10は数値として、testという文字列はtestという文字列で扱われることになる。
  • <?php
    <a href="?a[]=1&a[10]=5&a[test]=10">link</a>
    ?>
  • pg_affected_rows関数はDELETEをクエリで実行した際に影響を受けた行数を返す関数である。これを利用して削除処理の成功/不成功を判定することができる。
  • ini_get関数でクッキーを使っているか確認できる。session_get_cookie_params関数でクッキーのパラメータを取得し、session_name()関数の返り値となるセッション名に空文字を設定することでセッションIDをクリアできる。サーバ上のセッションファイルはsession_destroy関数を呼び出せばOK。
  • トランザクション機能を使うと、一連の処理におけるSQLの実行が途中で失敗しても、その処理の直前までもとに戻すことができる。
  • <?php
    pg_query(コネクション名, 'BEGIN');
    (ここに書いたSQL文がトランザクションになる)
    pg_query(コネクション名, 'COMMIT');
    ?>

2014年10月25日土曜日

PHPmemo_day14

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第13章(処理制御)です。Smartyなど素のPHPとは関係のないところは省略。

  • スクリプトを途中で終了する場合にはexit関数、die関数を使う。前者は終了時にエラーメッセージを出さないのに対し、後者は終了時にエラーメッセージが出てくるようになっている。関数の引数に文字列を与えることでエラー時のメッセージを制御することができる。また、関数を引数に与えることで異常時でも正常終了させるなどすることができる。
  • 処理を一時停止するにはsleep関数を使う。これは秒単位で停止する。マイクロ秒単位で制御する場合はusleep関数を用いる。
  • エラーメッセージの抑制は変数、関数の前に@マークをつけることでできる。例えば@num = 10/0;のようにすればnumに関するエラーメッセージは出なくなる。
  • error_reporting関数はエラーを表示させるレベルを設定できる。関数を呼出した後からレベルが変化する。
  • error_log関数はエラーメッセージを任意のファイルに送信することができる。Webサーバのログ、メールなどにも書き込める。
  • trigger_error関数を使うと、ユーザエラーを発生させることができる。このとき、引数にE_USER_ERRORを指定することになる。
  • header関数でHTTPヘッダを送信することが可能になる。例えばLocationヘッダを指定することで移動先のURLを指定できる。
  • exec関数を利用すると外部プログラムを実行する。exec関数は返り値を要求しない場合に使う。system関数は標準出力を返してくる。
  • 外部プログラムでシェルを使うときはescapeshellargでシェル引数として与える文字列をエスケープしなければならない。これはexec、system関数の両方に対して言える。

フォロワー

ページビューの合計