KITA Eng.

北海道でサーバー技術者として歩み出したひとが綴るblog。

PostfixAdmin的なものを作ってみた。

1台のメールサーバーで複数ドメイン運用したり、システムアカウントと連動せずにメールアカウント運用したいとかのときに、便利なPostfixAdmin( Postfix Admin - Web based administration interface)さん。

わたくしもお世話になっておりましたが、MySQLPostgreSQLと一緒にメールサーバーを動かしてあげないといけないのが面倒になってきた今日この頃...。LXDコンテナで流浪人のように移動しやすいコンテナとしておきたいわけです。もちろんMySQLでもPostgreSQLでもコンテナごと動かす分にはいんですけど、システムリソース的に...ということで...。

そんなオレオレ要件を満足させるものを作ってみました。 github.com

バーチャルメールユーザー管理画面

f:id:kacchan822:20160911135015p:plain

バーチャルメールユーザーの変更画面

f:id:kacchan822:20160911135033p:plain

バーチャルメールエイリアス管理画面

f:id:kacchan822:20160911135020p:plain

バーチャルメールエイリアスの変更画面

f:id:kacchan822:20160911135448p:plain

バーチャルメールドメイン管理画面

f:id:kacchan822:20160911135023p:plain

バーチャルメールドメインの変更画面

f:id:kacchan822:20160911135511p:plain

今回使ったもの

Pythonの軽量フレームワークのBottleをメインにして、UI部分と入力制御系をJavascriptで実装してみました。
本当は、PostfixAdmin的にユーザーログインによる認証機構もつけようとしたのですが、オレオレツールとしては、取り急ぎ必要ではないという英断により、未実装。これからお勉強がてら実装したいです。
Cork - Authentication for the Bottle web frameworkというのを使えばよさげかなと思っています。

今回、ちょっと積極的にcodeclimateさんのチェックを通しながらやったら、確かにコードが短くなったり煩雑だったところがすっきりとしました。(最初のコーディングが美しくな過ぎたというのはさておき....pythonやら、javascriptやら、jQueryやら、PostfixやらDovecotやらsqlite3やらいろんな勉強になったので、個人的には満足です。(これってよくあるダメなやつじゃないか...)

いうまでもなく、現状としてはデバックもかねて、SSHトンネル経由でbottleの簡易サーバー機能をそのまま使って動かしているレベルなので、実運用レベルにはありません。


ちなみにGoogle先生に「postfixadmin sqlite」尋ねてみたら、こんなのがあった。

github.com

2010年3月ごろからある模様。MySQLやらPostgreSQLやらを使ってやるまでの規模じゃないんだけど...なことはそりゃ考えるよな。


(2016.09.15 追記)

2016/09/12にPostfixAdmin3.0がついにリリースされたようで、なんと、add sqlite backend optionと言っているので、動作検証していないけどsqliteでも使えるようになったようです。

sourceforge.net

0. Raspberry Pi3 の初期セットアップ

Raspbery Pi3のセットアップの記事を探すとさくっと出てくるのはディスプレイを繋いで、マウスとキーボード繋いで式だったりしますが...

HDMIの繋がるディスプレイなんてないよ!」
でも大丈夫!僕らにはSSHがあるじゃないか。

「有線LANとか繋ぐのだるくね?」
でも大丈夫!wifiの設定ファイルを書いちゃっとけばいいじゃないか。

という我が家の環境を鑑みたバージョンでお送りします。

Raspbianイメージの書き込まれたmicroSD作成

1. OSイメージファイルのダウンロード

Download Raspbian for Raspberry Pi
素直にRaspbianにしておく。あとでリモートデスクトップとか別所で画面つないで使うこともあるので、「Full desktop image based on Debian Jessie」の方を利用。

2. OSイメージをmicroSDに書き込む

Installing operating system images - Raspberry Pi Documentation
公式殿のドキュメントにしたがってやればよい。Ubuntu16.04環境でやると以下のような流れ。

## SDカードのマウント状況確認
kacchan822@ubuntu16:~$ df -h
Filesystem                   Size  Used Avail Use% Mounted on
udev                         7.8G     0  7.8G   0% /dev
tmpfs                        1.6G  9.5M  1.6G   1% /run
/dev/mapper/ubuntu--vg-root  101G   45G   52G  47% /
tmpfs                        7.8G  390M  7.4G   5% /dev/shm
tmpfs                        5.0M  4.0K  5.0M   1% /run/lock
tmpfs                        7.8G     0  7.8G   0% /sys/fs/cgroup
/dev/sda2                    237M  171M   54M  77% /boot
/dev/sda1                    511M  3.6M  508M   1% /boot/efi
cgmfs                        100K     0  100K   0% /run/cgmanager/fs
tmpfs                        1.6G   80K  1.6G   1% /run/user/1000
/dev/mmcblk0p1                15G  8.0K   15G   1% /media/kacchan822/9779-6F81


## microSD(/dev/mmcblk0p1)がマウントされていたのでマウント解除
kacchan822@ubuntu16:~$ umount /dev/mmcblk0p1

### マウント解除されたのを一応確認
kacchan822@ubuntu16:~$ df -h
Filesystem                   Size  Used Avail Use% Mounted on
udev                         7.8G     0  7.8G   0% /dev
tmpfs                        1.6G  9.5M  1.6G   1% /run
/dev/mapper/ubuntu--vg-root  101G   45G   52G  47% /
tmpfs                        7.8G  390M  7.4G   5% /dev/shm
tmpfs                        5.0M  4.0K  5.0M   1% /run/lock
tmpfs                        7.8G     0  7.8G   0% /sys/fs/cgroup
/dev/sda2                    237M  171M   54M  77% /boot
/dev/sda1                    511M  3.6M  508M   1% /boot/efi
cgmfs                        100K     0  100K   0% /run/cgmanager/fs
tmpfs                        1.6G   80K  1.6G   1% /run/user/1000


### ダウンロードしたOSイメージファイルのディレクトリへ移動・ファイル存在確認
kacchan822@ubuntu16:~$ cd Downloads/
kacchan822@ubuntu16:~/Downloads$ ls
2016-05-27-raspbian-jessie.img


## OSイメージの書き込み
### さっきのアンマウントしたのは、「/dev/mmcblk0p1」だけど、書き込み先としては、「/dev/mmcblk0」になるので注意って公式ドキュメントも言っている。
kacchan822@ubuntu16:~/Downloads$ sudo dd bs=4M if=2016-05-27-raspbian-jessie.img of=/dev/mmcblk0
[sudo] password for kacchan822: 
958+1 records in
958+1 records out
4019191808 bytes (4.0 GB, 3.7 GiB) copied, 859.35 s, 4.7 MB/s

## 公式殿にはこのあとmd5チェックサムで書込結果の検証する方法が紹介されているけど、大丈夫だと信じて割愛。
3. Wi-fiの設定ファイルを編集する。

2.でOSイメージを書き込んだSDカードをマウントし直す。コマンドでやればいい気もするけど、一回抜いて、挿し直せば自動でマウントしてくれるはず。

「boot」と「2f840c69-cecb-4b10-87e4-01b9d28c231c」というようなのがマウントされるので、長ったらしい名前の方のマウントされている方の中にあるwifiの接続設定ファイルを編集れば、有線で最初に一度繋がなくていい。

## 設定ファイルのあるディレクトリへ移動
kacchan822@ubuntu16:~$ cd /media/kacchan822/2f840c69-cecb-4b10-87e4-01b9d28c231c/etc/wpa_supplicant/

## 設定ファイルを開く(root権限(SUDO)で開く必要がある。)
kacchan822@ubuntu16:/media/kacchan822/2f840c69-cecb-4b10-87e4-01b9d28c231c/etc/wpa_supplicant$ sudo vi wpa_supplicant.conf 

設定ファイルを以下のように編集する。

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
    ssid="接続するwifiのSSID"
    psk="接続するwifiのパスワード"
    key_mgmt=WPA-PSK
}

countryは後でも直せるけどついでなのでJPにしておく。 wifiのセキュリティ設定によって、少し設定値が変わってくるだろうけど、 wpa_supplicant.conf(5) - Linux man pageを参考にすれば大丈夫かなと。

完成!

取り出しておく。

Raspbery Pi3を起動してSSH接続

1. OS起動!

f:id:kacchan822:20160813145901j:plain OSイメージの入ったmicroSDをRaspberry Pi3に差し込んで、microUSBで給電するとピカピカと、赤および緑のランプが光って起動を始める。緑のランプの点滅が落ち着いた頃合いでsshしてあげるとよさ気。

2. SSHで接続

IPアドレスDHCPで割り当てられるだろうので(固定にしたかったら、wifiの設定をした流れでついでにネットワークせってファイルもいじっとけばいいだろう)、ipアドレスがわからないが、、、

kacchan822@ubuntu16:~$ ssh pi@raspberrypi.local

と叩けば、うまいこと見つけて接続してくれる。初期パスワードは「raspberry」なので、パスワードを聞かれたら入力してあげるとログインできる。

とりあえずアップデートとか

ログインできたらとりあえず、初期パスワードからログインパスワードを変更したり、ソフトウェアアップデートをしたり、raspberrypiの設定値をいろいろ調整したりしておく。

## ログインパスワード変更
pi@raspberrypi:~ $ passwd

## アップデート(結構時間かかる)
pi@raspberrypi:~ $ sudo apt-get update
pi@raspberrypi:~ $ sudo apt-get upgrade

## 設定値の変更
pi@raspberrypi:~ $ sudo raspi-config 

ひとまずこんなところでしょうか。raspi-configの各種設定値はお好みで。Expand Filesystemは、32GB、16GBのは特にしなくてもうまいことなっている感じだった。

kitaeng.hateblo.jp

Raspberry Pi3 で子どもたちと「遊ぶ」までの道のり(とりあえず自分で遊んでみる編)

前々から気になっていたRaspberry Piですが、なんだかんだとウダウダしていて、なかなかポチッとなしてなかったのですが、実験やらプログラミングやら電子工作やらして子どもらと遊ぶことになったので、ついに購入。

子どもらとどうやって遊ぶかも含めて、まずは自分で遊び倒してみることにしたはいいが、やれることが無限大すぎて、どこから手をつけたらいいものやらなので、Raspberry Pi3と一緒に注文してみた、以下のキットに含まれる部材でできることをいろいろやってみることにする。

amzn.to

とりあえず以下予定。

  • 0. Raspberry Pi3 の初期セットアップ
  • 1. Raspberry Pi3 でLEDをチカチカ
  • 2. Raspberry Pi3 でLCDに文字表示
  • 3. Raspberry Pi3 で温度センサーで室温取得
  • 4. Raspberry Pi3 でフルカラーLEDをチカチカ
  • 5. Raspberry Pi3 でモーター制御
  • 6. Raspberry Pi3 でサーボモーター制御

Apache 2.4 + MariaDB 5.5 でmod_dbd を使ったDigest認証の設定をしてみた。

使いどころがあるのか謎だけど、Apacheの認証系でもDB連携あるぞというのをたまたまみかけたので、やってみた。

環境

必要なパッケージのインストール

DBドライバーのインストール。今回は、MariaDBで試すので、apr-util-mysqlをインストール。

Daigest認証用のDB.TABLE作成、ユーザーデータ登録

まずDBとテーブルを作る

DB名:apacheauth (任意)
TABLE名:digest_auth_users (任意)

CREATE DATABASE apacheauth;

CREATE TABLE digest_auth_users (
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    user VARCHAR(255) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    realm VARCHAR(255) DEFAULT 'AuthRequirePage'
);

** realmは後にApacheの設定でAuthNameで指定する文字列。

Apacheからデータを参照するためのDB接続ユーザーを作成する

基本的には参照権限だけあれば十分。プログラムで動的に変更するなど操作を同じユーザーでさせるならば、UPDATEやDELETEも権限を与えてあげる。

GRANT SELECT ON apacheauth.* TO 'apache'@'localhost' identified by 'apache';
テスト用のユーザーデータを入れる

セキュアじゃないけど今回はDB上には平文のパスワードを保持させることにした。

INSERT INTO digest_auth_users ( user, password ) VALUES ( "test", "test" );
id user password realm
1 test test AuthRequirePage

Apacheの設定

conf/httpd.conf(またはconf.d/<任意の名称>.conf)または、VirtualHostディレクティブ内 に以下の記述を行う。

DBD~の部分は、Directoryディレクティブの中には書けないので注意。
参照 --> mod_dbd - Apache HTTP Server Version 2.4

DBDriver mysql
DBDParams "host=localhost,dbname=apacheauth,user=apache,pass=apache"
DBDMin 2
DBDKeep 2
DBDMax 10
DBDExptime 300

<Directory "/var/www/auth_html">
    Options Indexes FollowSymLinks
    AllowOverride None
    Require valid-user
    AuthType Digest
    AuthDigestAlgorithm MD5
    AuthName "AuthRequirePage"
    AuthDigestProvider dbd
    AuthDBDUserRealmQuery "SELECT MD5(CONCAT(user, ':', realm, ':', password)) AS password FROM digest_auth_users WHERE user = %s AND realm = %s"
</Directory>

今回はDBには平文でパスワードを保存したので、AuthDBDUserRealmQueryの部分でDB問合せ時に、Apachemod_auth_digestが求める形のパスワード形式(user:realm:passwordMD5ハッシュした32文字列)
参照 --> Password Formats - Apache HTTP Server Version 2.4

%sには、前から順に入力されたuser名AuthNameの値が入る。

一応SQLの部分だけ抜き出しておくとこんな感じ。

SELECT
  MD5(
   CONCAT(user, ':', realm, ':', password)
  ) AS password
FROM digest_auth_users
WHERE user = %s AND realm = %s

%sに入る値は、mod_dbdでうまいことSQLインジェクション対策として不正な文字列はエスケープしてくれるらしい。
参照 --> mod_dbd - Apache HTTP Server Version 2.4

完了!

あとはApacheの再起動をして設定を反映させればよい。

アルファベット文字列をフォネティックコードで表記するPythonモジュールをつくったよ:a2pcej

アカウントの追加業務とかで、パスワードをこちらで適当に生成してお知らせるときに、パスワード文字列のよみがなをつけて渡すということが、しばしばあるわけです。

たとえば、こんなやつ。

ユーザー名: hogehoge
パスワード: WPzm60zh (ダブリュー(大文字)・ピー(大文字)・ゼット・エム・ロク・ゼロ・ゼット・エイチ)

大した数じゃなければ手打ちするのもいいんですが、一気にどかっと発行するとかなると手打ちするは厄介です。自動でやってしまいたいところです。

Google先生に尋ねると、

といったのが出てきます。パスワードの生成からやってしまってよければ、フリガナつきパスワード生成ツール - Password Generator は、大量生産できるのでよさ気ですが...

パスワードのよみがなの区切り文字や、大文字につける表記が自分のところで使っているフォーマットと合わなかった...

ということで、実はずい分前に手元で使える用には、ざっくりpythonスクリプトで作ってありました

今回これを大改造して、

  • 区切り文字を指定できる
  • 大文字につける印を指定できる
  • カタカナ表記だけではなく、英語圏用(?)にフォネティックコード表記できる

というものを作ってみました。いろんなところで使いまわしやすいように、PyPIに上げて、pipでインストールできるようにしました。 謎のネーミングセンスにより、a2pcejという名称にしました。一応、convert Alphabet to Phonetic Code in English and Japaneseの略。

使い方

以下Python3.5環境での出力例です。関数の戻り値はunicode文字列になっています。

兎にも角にもモジュールをインポート。
>>> from a2pcej import *
アルファベットの文字列にカタカナでよみがなをつける。 :conv_ak()
>>> conv_ak('examples')
'イー・エクス・エイ・エム・ピー・エル・イー・エス'

アルファベット大文字にはデフォルトで「(大文字)」と付く。
アルファベット以外(記号や数字)はデフォルトだとよみがな変換されない(その文字がそのままま出る)。

>>> conv_ak('Examples002')
'イー(大文字)・エクス・エイ・エム・ピー・エル・イー・エス・0・0・2'

区切り文字を変更するには、delimiter='文字列'を引数に追加する。
アルファベット大文字につく文字列の変更をするには、 sign='文字列'を引数に追加する。
空にすれば、区切りなし、大文字表記なしになる。

>>> conv_ak('Examples003', delimiter='/', sign='(大)')
'イー(大)/エクス/エイ/エム/ピー/エル/イー/エス/0/0/3'

>>> conv_ak('Examples003', delimiter='', sign='')
'イーエクスエイエムピーエルイーエス00'

数字にもよみがなを付けたいときは、num=Trueを引数に加える。

>>> conv_ak('Examples004', num=True)
'イー(大文字)・エクス・エイ・エム・ピー・エル・イー・エス・ゼロ・ゼロ・ヨン'
アルファベットの文字列に英単語のフォネティックコードをつける。 :conv_al()

オプションは、 conv_ak()と同じなので、出力例だけ。 区切り文字、大文字につく文字列のデフォルトを英語圏っぽいのにしてある。

>>> conv_al('examples')
'Echo-Xray-Alfa-Mike-Papa-Lima-Echo-Sierra'

>>> conv_al('Examples002')
'Echo(CAPS)-Xray-Alfa-Mike-Papa-Lima-Echo-Sierra-0-0-2'

>>> conv_al('Examples003', delimiter=', ', sign='(CAPITAL)')
'Echo(CAPITAL), Xray, Alfa, Mike, Papa, Lima, Echo, Sierra, 0, 0, 3,'

>>> conv_al('Examples004', num=True)
'Echo(CAPS)-Xray-Alfa-Mike-Papa-Lima-Echo-Sierra-zero-zero-four'

ソース

github.com

PyPI

pypi.python.org


雑感

python2での文字コードのこととか、パッケージングする方法とか、pandocってなんか便利なツールがあるとか、いろいろお勉強になりましたです。久しぶりに英文も書いたらスペルミスと謎の構文の嵐です。