2015/05/21

CloudFormationのパラメータタイプが増えた

CloudFormationのテンプレートで使えるパラメータタイプが増えたようです。

リリースノートにも出ていました。
AWS CloudFormation - Release History


以前から書いてあったのは下記の7種類でした。
  • AWS::EC2::KeyPair::KeyName
  • AWS::EC2::SecurityGroup::Id
  • List<AWS::EC2::SecurityGroup::Id>
  • AWS::EC2::Subnet::Id
  • List<AWS::EC2::Subnet::Id>
  • AWS::EC2::VPC::Id
  • List<AWS::EC2::VPC::Id>
上記に加え、2015年5月19日からは下記のものも使えるようです。
  • AvailabilityZoneの名称
    • AWS::EC2::AvailabilityZone::Name
    • List<AWS::EC2::AvailabilityZone::Name>
  • インスタンスID
    • AWS::EC2::Instance::Id
    • List<AWS::EC2::Instance::Id>
  • イメージID
    • AWS::EC2::Image::Id
    • List<AWS::EC2::Image::Id>
  • セキュリティグループ名
    • AWS::EC2::SecurityGroup::GroupName
    • List<AWS::EC2::SecurityGroup::GroupName>
  • EBSボリュームID
    • AWS::EC2::Volume::Id
    • List<AWS::EC2::Volume::Id>
  • Route53のHostedZoneID
    • AWS::Route53::HostedZone::Id
    • List<AWS::Route53::HostedZone::Id>
また、実際にテンプレート内で使用した際のLook&Feelも改善されているようです。
UIの話なのでもちろんすべてのパラメータタイプで改善されています。
なお、AWS::EC2::Image::IdについてはドロップダウンUIが出ない旨の注意書きがあります。
おそらくは、パブリックイメージ、プライベートイメージ、オーナーイメージの区分をどう実現するか、といったところが設計的もしくはUI的に決め切れていないものと思われます。
もしかすると、AMIについては将来的にタイプが変更されるかもしれませんね(根拠なし)。

リソースセクションでパラメータを使えるようにしてほしいなどまだまだ要望はありますが、少しずつ実現できる項目が増えてくれるのは良いですね。

2014/09/26

AWS::IAMのロールを使う


最近AWSをぼちぼちさわっております。

クラウド環境でAPIが使えることで夢広がりingなのはいいんですが、昔はAPIリクエスト時にアクセスキーを埋め込んでいたものの、メンテナンス性やセキュリティの面からちょっと、と思っていたので、コマンドでたたくことはあってもスクリプト化するのはちょっとためらっていました。

時は流れてIAM(Identity and Access Management)が登場、インスタンスに対してロールを関連付けることができ、前述の難点も改善されています。
というわけで、今回はIAMでちょっと遊んでみました。



Roleを作る


webコンソールから作ってみましょう。
IAM > Rolesと進んで、「Create Role」を選択します。
名前は適当に「MinimumRole」とでもしておきます。ポリシーの中身はこんな感じで。
最低限、ec2::DescribeInstancesのみを許可しておきます。今回は、リソースに対する制限は行いません。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeInstances"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

インスタンスに割り当てる


作成したら、インスタンスに割り当てましょう。
普段のお好みにかかわらず、Amazon Linuxで起動するのがベターです。Amazon Linuxは最初からコマンドラインツールが入っていますからね。なお、一度作成したEC2インスタンスへのRoleの割り当てはあとから差し替えできませんので悪しからず。

ちなみに、インスタンスに割り当てるのは(正確にいえば)RoleではなくInstanceProfileです。
また、InstanceProfileに対するRoleの追加/削除は可能なようですが、一度作成したEC2インスタンスに対するInstanceProfileの差し替えは無理なようです。(APIを見る限りそうっぽい)
が、記事を書いている時点でここに下記のようなことが書いてありますので、今回はいったん同一のものとして扱います。
If you use the AWS Management Console to create a role, the console creates an instance profile automatically and gives it the same name as the role it corresponds to. However, if you use the CLI, API, the AWS SDK, or a third-party tool to create roles and instance profiles, you create the roles and instance profiles as separate actions, and you might give them different names. In that case, you need to know the names of your instance profiles as well as the names of roles they contain so that you can choose the correct instance profile when you launch an Amazon EC2 instance.
【俺訳】コンソールを利用してroleを作成する場合、自動的に同一名のinstance profileが作成されますが、それ以外(CLI、API、SDK、サードパーティツールなど)で作成する場合、roleとinstance profileそれぞれの作成は別アクションとなります。roleとinstance profileに別の名前を付与して関連付けた場合、EC2インスタンスの作成時に、必要なroleを含んだ適切なinstance profileを指定する必要があります。

いざためす


というわけで、作成したらec2-userでログインし、いきなり実行してみましょう。

$ aws ec2 describe-instances
You must specify a region or set the AWS_DEFAULT_REGION environment variable. You can also configure your region by running "aws configure".

あらあら。文句を言われてしまいました。最低限リージョンは必要なようです。
aws configureはあとでやるとして、気を取り直してもう一度。

$ aws ec2 describe-instances --region us-west-2
{
    "Reservations": [
        {
            (ここは省略)
        }
    ]
}
ちゃんと出てくるようになりました。

configureする


プログラムから実行するときはあらかじめリージョンを指定しておけばいいのですが、CLIで毎回入力するのはちょっと面倒なので、aws configureをやって覚えさせましょう。

$ aws configure
AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]: us-west-2
Default output format [None]:

リージョン以外は入力していませんが、それでいいんです。
EC2インスタンスに対してRole(正確にはInstanceProfile)が関連付けられているので、ここでアクセスキーを埋め込まなくても大丈夫なんです。
ちなみに、ここでconfigureした結果は「~/.aws/config」に保存されます。やり直したい場合はこのファイルを消せば初期化されます。
また、ホームディレクトリに作成されますので、複数ユーザで実行する場合はユーザごとにaws configureを実行する必要があります。
#/etc/aws/configは認識してくれませんでした。危険な情報を埋め込んでいるので、当然と言えば当然です。

初期リージョンを覚えこませましたので、今度はリージョン指定がなくても通るはず。

$ aws ec2 describe-instances
{
    "Reservations": [
        {
            (ここは省略)
        }
    ]
}

まとめっぽい


これで、インスタンスから発行されるAPIの権限管理に関して、スクリプトをいじる必要がなくなりましたね。

スクリプトごとに権限を変える場合はどうするのかって?
一つのインスタンスが持つ役割(=Role)は単一化したほうが管理しやすくありませんか?

2013/12/10

redmineのREST APIを利用してwikiページを作成するときのメモ

普段PUTリクエストなんて使わないのでよくわかりませんでした。
いろいろ試行錯誤したので、取り急ぎメモだけ。

#!/usr/bin/ruby

require 'net/http'
require 'uri'

api_key = 'fxcxaxfxcx9x2x4xdxdx1x8x3xbxbxdx4x4x1xfx0x2x3'
redmine_base = 'http://127.0.0.1:3000'
project_identifier = 'tteesstt'
wiki_title = 'testpage2'
request_path = '/projects/' + project_identifier + '/wiki/' + wiki_title +'.xml'
wiki_body  = ''
wiki_body << ''
wiki_body << ''
wiki_body << 'hogefuga'
wiki_body << 'ahhahha'
wiki_body << ''

url = URI.parse(redmine_base + request_path)
req = Net::HTTP::Put.new(url.path)
req['Content-Type'] = 'text/xml'
req['X-Redmine-Api-Key'] = api_key
req.body = wiki_body

res = Net::HTTP.start(url.host, url.port){ |http| http.request(req) }
p res.body

2013/10/09

z-pushとの闘い

まずは何も考えずダウンロードしてみる。

http://z-push.sourceforge.net/soswp/

# tar xzf z-push-2.1.0-1750.tar.gz
# cd z-push-2.1.0-1750
# ls
INSTALL  LICENSE  backend  config.php  include  index.php  lib  tools  version.php  z-push-admin.php  z-push-top.php

とりあえずINSTALLを読む。

サーバ要件:PHP5.1以上

ということは、PHP5.1とapacheの環境があればよいということか。

まずはDNS名(app.example.net)を用意する。

続いて鍵+証明書を作り、これをSSLサイトに食わせておく。

# openssl req -x509 -days 365 -newkey rsa:2048 -nodes -keyout app.example.net.key -out app.example.net.crt

インストールは書いてある通りにやってみよう。prefixは/usr/localにしてみる。
# sudo tar xzf z-push-2.1.0-1750.tar.gz -C /usr/local/share
# mkdir /var/lib/z-push /var/log/z-push
# chown apache:apache /var/lib/z-push /var/log/z-push
# vi /etc/httpd/conf.d/ssl.conf
# httpd -t
# service httpd reload

--- /etc/httpd/conf.d/ssl.conf      (before)
+++ /etc/httpd/conf.d/ssl.conf      (after)
@@ -81,5 +81,14 @@
        AllowOverride   all
   </Directory>

+
+       Alias /Microsoft-Server-ActiveSync /usr/local/share/z-push/index.php
+  <directory /usr/local/share/z-push>
+       php_flag magic_quotes_gpc off
+       php_flag register_globals off
+       php_flag magic_quotes_runtime off
+       php_flag short_open_tag on
+  </Directory>
+
  </VirtualHost>
 </IfModule>
というわけで、予想通りはまる。
なんか言ってる。
PHP-MAPI extension is not available

調べてみたところ、一部のパッケージが足りていなかったもよう。
# yum install php-imap php-soap php-process

と思ったら、php-processはPHP5.3のパッケージなのね。
あきらめて、php-*系のパッケージを全部捨てて、php53-*をインストール。

# rpm -e php php-たくさん
# yum install php-process php

やってみたがまだ動かぬ。
php-mapiってどこにあるんだよ!!
とりあえず「php-mapi rpm」で適当に探してくる。

.....fedoraprojectに落ちてたぽい。

# rpm -ivh php53-mapi-7.0.13-1.el5.i386.rpm
エラー: 依存性の欠如:
libicudata.so.36 は php53-mapi-7.0.13-1.el5.i386 に必要とされています
libicui18n.so.36 は php53-mapi-7.0.13-1.el5.i386 に必要とされています
libicuuc.so.36 は php53-mapi-7.0.13-1.el5.i386 に必要とされています
libinetmapi.so.1 は php53-mapi-7.0.13-1.el5.i386 に必要とされています
libmapi.so.0 は php53-mapi-7.0.13-1.el5.i386 に必要とされています

ぬおー。片っ端から探していれちまえ。
# rpm -ivh libmapi-7.0.13-1.el5.i386.rpm php53-mapi-7.0.13-1.el5.i386.rpm
エラー: 依存性の欠如:
libboost_filesystem-mt.so.5 は libmapi-7.0.13-1.el5.i386 に必要とされています
libboost_system-mt.so.5 は libmapi-7.0.13-1.el5.i386 に必要とされています
libical.so.0 は libmapi-7.0.13-1.el5.i386 に必要とされています
libicalss.so.0 は libmapi-7.0.13-1.el5.i386 に必要とされています
libvmime.so.0 は libmapi-7.0.13-1.el5.i386 に必要とされています
zarafa-client = 7.0.13-1.el5 は libmapi-7.0.13-1.el5.i386 に必要とされています

えー。zarafa-clientが出てきたってことは、結局zarafaから落とした方がいいの?
でもさっきからEPELのパッケージ使ってるし….よし、ポリシーを緩めてEPEL解禁!
# rpm -ivh epel-release-5-4.noarch.rpm
# yum install php53-mapi
Dependencies Resolved
========================================================================================================================
Package                           Arch               Version                                  Repository          Size
========================================================================================================================
Installing:
php53-mapi                        i386               7.0.13-1.el5                             epel               217 k
Installing for dependencies:
boost141-filesystem               i386               1.41.0-4.el5                             epel                73 k
boost141-system                   i386               1.41.0-4.el5                             epel                25 k
libgsasl                          i386               0.2.29-1.el5                             epel               100 k
libical                           i386               0.48-1.el5                               epel               202 k
libmapi                           i386               7.0.13-1.el5                             epel               904 k
libntlm                           i386               1.0-1.el5                                epel                43 k
libvmime                          i386               0.9.2-0.1.20110626svn.el5                epel               887 k
zarafa-client                     i386               7.0.13-1.el5                             epel               1.3 M
zarafa-common                     i386               7.0.13-1.el5                             epel                22 k
Transaction Summary
========================================================================================================================
Install      10 Package(s)
Upgrade       0 Package(s)
Total download size: 3.7 M

Is this ok [y/N]: 

まぢで?そういうオチ?
とりあえず入れてみる…..入った。
気を取り直してapacheリロード。
# httpd -t
Syntax OK
# service httpd reload

とりあえず500はなくなった。

続いて、config.phpをいじって、imapバックエンドを使うように変更。
--- /usr/local/share/z-push/config.php     (before)
+++ /usr/local/share/z-push/config.php     (after)
@@ -45,7 +45,7 @@
*  Default settings
*/
// Defines the default time zone, change e.g. to "Europe/London" if necessary
-    define('TIMEZONE', '');
+    define('TIMEZONE', 'Asia/Tokyo');
// Defines the base path on the server
define('BASE_PATH', dirname($_SERVER['SCRIPT_FILENAME']). '/');
@@ -90,7 +90,7 @@
define('LOGFILE', LOGFILEDIR . 'z-push.log');
define('LOGERRORFILE', LOGFILEDIR . 'z-push-error.log');
define('LOGLEVEL', LOGLEVEL_INFO);
-    define('LOGAUTHFAIL', false);
+    define('LOGAUTHFAIL', true);


// To save e.g. WBXML data only for selected users, add the usernames to the array
@@ -185,7 +185,7 @@
*  Backend settings
*/
// the backend data provider
-    define('BACKEND_PROVIDER', '');
+    define('BACKEND_PROVIDER', 'BackendIMAP');

/**********************************************************************************
*  Search provider settings

んで、imap側のconfig.phpもいじる。
--- /usr/local/share/z-push/backend/imap/config.php     (before)
+++ /usr/local/share/z-push/backend/imap/config.php     (after)
@@ -46,13 +46,13 @@
// ************************

// Defines the server to which we want to connect
-define('IMAP_SERVER', 'localhost');
+define('IMAP_SERVER', '127.0.0.1');
// connecting to default port (143)
-define('IMAP_PORT', 143);
+define('IMAP_PORT', 993);
// best cross-platform compatibility (see http://php.net/imap_open for options)
-define('IMAP_OPTIONS', '/notls/norsh');
+define('IMAP_OPTIONS', '/tls/norsh');

// overwrite the "from" header if it isn't set when sending emails
// options: 'username'    - the username will be set (usefull if your login is equal to your emailaddress)

で、iPhone側でExchangeアカウントをセット。
やってみるが"Connection Serfer Failed."などと言って一歩も動かない。
アカウント追加時の認証チェックは通っていたぽいので、パスワード周りは間違っていないはず。。。

しかし動かず。
とりあえず、いろんなところのデバッグフラグをONにしてみる。

--- /usr/local/share/z-push/config.php (before)
+++ /usr/local/share/z-push/config.php (after)
@@ -89,7 +89,7 @@
     define('LOGFILEDIR', '/var/log/z-push/');
     define('LOGFILE', LOGFILEDIR . 'z-push.log');
     define('LOGERRORFILE', LOGFILEDIR . 'z-push-error.log');
-    define('LOGLEVEL', LOGLEVEL_INFO);
+    define('LOGLEVEL', LOGLEVEL_DEBUG);
     define('LOGAUTHFAIL', true);

--- /usr/local/share/z-push/config.php  (before)
+++ /usr/local/share/z-push/config.php  (after)
@@ -52,7 +52,7 @@
 define('IMAP_PORT', 993);

 // best cross-platform compatibility (see http://php.net/imap_open for options)

-define('IMAP_OPTIONS', '/tls/norsh');
+define('IMAP_OPTIONS', '/tls/norsh/debug');

 // overwrite the "from" header if it isn't set when sending emails
 // options: 'username'    - the username will be set (usefull if your login is
equal to your emailaddress)

しかしまだ動かない。
webでアクセスしてみても、しばらく待ってから再度認証を求められ、その直前に下記のようなログが出る。
/usr/local/share/z-push-2.1.0-1750/backend/imap/imap.php:99 imap_open(): Couldn't open stream {127.0.0.1:993/imap/tls/norsh/debug} (2)

気づいた。オレオレ証明書じゃん。
というわけで、接続オプションを変更。
--- /usr/local/share/z-push/config.php  (before)
+++ /usr/local/share/z-push/config.php  (after)
@@ -52,7 +52,7 @@
 define('IMAP_PORT', 993);

 // best cross-platform compatibility (see http://php.net/imap_open for options)

-define('IMAP_OPTIONS', '/tls/norsh/debug');
+define('IMAP_OPTIONS', '/tls/norsh/novalidate-cert');

 // overwrite the "from" header if it isn't set when sending emails
 // options: 'username'    - the username will be set (usefull if your login is
equal to your emailaddress)
まだ動かない。
imap_open()でコケると言っているが、dovecotのログがぜんぜんにぎやかじゃない。どーゆーことだ???
ということは、認証かセッション確立でこけてると予想。
imap_open()を使って直接たたいてみる。

imap_open("{127.0.0.1/tls/norsh/novalidate-cert}INBOX", $username, $password);


しっかり60秒待ってからエラーが表示された。
うーん、セッション確立の影響だなぁ。

で、下記のように変えてみた。
--- /usr/local/share/z-push/config.php  (before)
+++ /usr/local/share/z-push/config.php  (after)
@@ -52,7 +52,7 @@
 define('IMAP_PORT', 993);

 // best cross-platform compatibility (see http://php.net/imap_open for options)

-define('IMAP_OPTIONS', '/tls/norsh/novalidate-cert');
+define('IMAP_OPTIONS', '/ssl/norsh/novalidate-cert');

 // overwrite the "from" header if it isn't set when sending emails
 // options: 'username'    - the username will be set (usefull if your login is equal to your emailaddress)

StartTLSによるSSL確立ではなく、最初からSSLで突っ込むようにしてみた。
お!動いた!!



というわけで、今回の反省。
いろんな環境を整理して調査にあたる必要がありますね。
  • imapのSSL状態。 どっちが直接の原因となるかは分からないけど、iPhoneでUse SSLを有効にしてるため、もしくはdovecot.confで「protocols=imaps」としているため、のいずれかもしくは両方の理由により、imap_open()のフラグに「/ssl」が必要。「/tls」ではだめ。
  • 証明書。 自前でやる場合はそんなにお金かけてられないので、往々にしてオレオレ証明書を利用することに。dovecotから見れば、z-pushは当然普通のクライアントなので、当然証明書はチェックされます。なので、人的介入無しに証明書エラーをくぐり抜ける必要があります。
  • ログはよく観察すること! いろんなログ(今回の場合はapache/dovecot/z-push)を見ましたが、特定のログだけを見ていても気づかないことが多いです。それぞれのコンポーネントがどのように連携しているのか?イベントが発生したタイミングで、どのログが流れてどのログが流れないのか?このあたりをちゃんと考慮してログを見ると、どこの部分でエラーが発生しているかのアタリがつけやすくなります。
というわけで、おしまいっ

2013/03/04

logwatchについてるpostfixのスクリプトをちょっと直してみた

logwatchでpostfixのログをパースさせてたんですが、最近Unmatched Entriesが増えてきたので、
Unmatchedを減らすべく、既存のフィルタを改造してみました。

対象にしたのはこれ。

# rpm -q logwatch
logwatch-7.3-9.el5_6

オリジナルを直接触るのは気が引けるので、ローカル用にコピーします。
# cp -p /usr/share/logwatch/scripts/services/postfix /etc/logwatch/scripts/services/
# vi /etc/logwatch/scripts/services/postfix

というわけで、オリジナル版のフィルタとdiffを取ってみました。

# diff -u /usr/share/logwatch/scripts/services/postfix /etc/logwatch/scripts/services/postfix
--- /usr/share/logwatch/scripts/services/postfix     2011-03-31 06:57:37.000000000 +0900
+++ /etc/logwatch/scripts/services/postfix     2013-03-02 10:37:16.000000000 +0900
@@ -224,7 +224,7 @@
    } elsif (($User) = ($ThisLine =~ /^[a-zA-Z0-9]+: to=\<([^ ]*)>,(?: orig_to=\<(?:[^ ]*)>,)? .*, status=bounced .*: User unknown in virtual (alias|mailbox) table/)) {
       # another unknown user probably could combine with local unknown but again my perl is weak
       $UnknownUsers{$User}++;
-   } elsif (($Dest, $Relay, $Msg) = ($ThisLine =~ /^[a-zA-Z0-9]+: to=\<([^ ]*)>,(?: orig_to=\<(?:[^ ]*)>,)? relay=([^ ]*).*, delay=-?[0-9]+, status=bounced \(([^)]*)/ )) {
+   } elsif (($Dest, $Relay, $Msg) = ($ThisLine =~ /^[a-zA-Z0-9]+: to=\<([^ ]*)>,(?: orig_to=\<(?:[^ ]*)>,)? relay=([^ ]*).*, delay=[^ ]*,(?: delays=[^ ]*,)?(?: dsn=[^ ]*,)? status=bounced \(([^)]*)/ )) {
       # unknown user
       # $Msg = " hello "
       # print "bounce message from " . $Dest . " msg : " . $Relay . "\n";
@@ -394,6 +394,10 @@
       $UnknownWarnings{$Warn}++;
    } elsif (($Host,$Filter) = ($ThisLine =~ /RCPT from ([^ ]*\[[^ ]*\]): <[^ ]*\[[^ ]*\]>: Client host triggers FILTER (\S*)/)) {
       $HostTrigFilter{"$Host,$Filter"}++;
+   } elsif ( ($Server, $Helo) = ($ThisLine =~ /^NOQUEUE: reject: RCPT from ([^ ]*\[[^ ]*\]): 450 4.7.1 Client host rejected: cannot find your hostname, [^ ]*; from=<[^ ]*> to=<[^ ]*> proto=[^ ]* helo=<([^ ]*)>$/)) {
+      $InvalidClientHostName{"$Server"}++;
+   } elsif ( ($Server, $Helo) = ($ThisLine =~ /^NOQUEUE: reject: RCPT from ([^ ]*\[[^ ]*\]): 504 5.5.2 <[^ ]*>: Helo command rejected: need fully-qualified hostname; from=<[^ ]*> to=<[^ ]*> proto=[^ ]* helo=<([^ ]*)>$/)) {
+      $InvalidHeloName{"RCPT from $Server: HELO=$Helo"}++;
    } else {
       push @OtherList,$ThisLine;
    }
@@ -691,6 +695,40 @@
    }
 }

+if (keys %InvalidClientHostName) {
+   if($Detail >= 5) {
+      print "\n\nInvalid client hostname:\n";
+      foreach $Message (sort {$a cmp $b} keys %InvalidClientHostName) {
+         print "   $Message: $InvalidClientHostName{$Message} Time(s)\n";
+      }
+   }
+   else {
+      $n=0;
+      $mn=scalar(keys %InvalidClientHostName);
+      foreach $Message (keys %InvalidClientHostName) {
+         $n+=$InvalidClientHostName{$Message};
+      }
+      print "\n\nInvalid client hostname:\n: $mn Message(s), $n Time(s)";
+   }
+}
+
+if (keys %InvalidHeloName) {
+   if($Detail >= 5) {
+      print "\n\nInvalid HELO command:\n";
+      foreach $Message (sort {$a cmp $b} keys %InvalidHeloName) {
+         print "   $Message: $InvalidHeloName{$Message} Time(s)\n";
+      }
+   }
+   else {
+      $n=0;
+      $mn=scalar(keys %InvalidHeloName);
+      foreach $Message (keys %InvalidHeloName) {
+         $n+=$InvalidHeloName{$Message};
+      }
+      print "\n\nInvalid HELO command:\n: $mn Message(s), $n Time(s)";
+   }
+}
+
 if (keys %LocalBounce) {
    if ($Detail >= 5) {
       print "\n\nLocal Bounce:\n";

各chunkのコメントです。
1つめ
bounceした記録の書式が多少変わっていたので、オリジナルの機能を失わないように正規表現を書き足してみました。
2つめ
postfixで下記の設定をした時に出るエラーに対応してみました。
  smtpd_client_restrictions = reject_unknown_client
  smtpd_helo_restrictions = reject_non_fqdn_hostname
3つめ
2つめでマッチしたログの出力部分です。

/etc/logwatch配下に置いたスクリプトは標準のスクリプトに優先して使われるようで、
期待通りの動作となりました。

2012/06/17

OpenLDAP2.4での設定スキームの移行

「そういえばdebianも6になったし、家のサーバも上げるか」という軽い気持ちで踏み出したdebian6。 ログをちゃんと確認しなかった自分が悪いんですが、後で見てみるとopenldapが2.3から2.4ベースに変わってる。 それよりも何よりもこのslapd.dディレクトリってなんじゃ?ってことになったので、軽く調べてみると.....。

OpenLDAP Software 2.4 Administorator's Guide: Configuring slapd
The older style slapd.conf(5) file is still supported, but its use is deprecated and support for it will be withdrawn in a future OpenLDAP release.
これまでのslapd.conf(5)形式のファイルは引き続きサポートされますが、この形式の利用は推奨されず、今後のOpenLDAPのリリースの中でいずれサポートされなくなる予定です。
がーん。slapd.conf使えなくなるんか。
これはslapd.confの保険があるうちにslapd-config(5)での設定変更方法を学んでおかなくちゃならんな。

上記ページのセクション5.1に設定用ツリーの概略が書いてあります。ってさらっと書いてあるけど、自分は実際の入っている状態を見てさわらないと理解できないおこちゃまなので、触ってみてはじめて意味が分かりました。
普段利用するdcである「dc=example,dc=com」の配下ではなく、これと独立した「cn=config」をトップとするツリーが生成・利用されるようです。

ここで疑問。「/etc/ldap/slapd.d配下にあるファイルは自分でインポートする用のテンプレートなのか?」
というわけでいろいろ試してみましたよ。

# ldapadd -x -W -D cn=admin,dc=example,dc=com -f cn\=config.ldif
Result: Insufficient access (50)
# ldapadd -x -W -D cn=config,cn=admin,dc=example,dc=com -f cn\=config.ldif
ldap_bind: Invalid credentials (49)
# ldapadd -x -W -D cn=config,cn=admin -f cn\=config.ldif
ldap_bind: Invalid credentials (49)
# ldapadd -x -W -D cn=config -f cn\=config.ldif
ldap_bind: Invalid credentials (49)

無理じゃん。どんなやったって入んないじゃん。
もう一度ドキュメントを読んでみるか。
slapd.d配下のファイルは手で直接いじるな....ですか。
ということは、net-snmpにおける/var/lib/net-snmp/snmpd.confと似たイメージで、メモリ上に保持されている各種設定の退避・保存先として使われるってことなのかな。
 もひとつ。-Fオプションと-fオプションについて。
  1. -fオプションのみの場合、slapd.confを使って動作してくれる。
  2. -Fオプションのみの場合、slapd.d配下の構成を使って動作してくれる。
  3. -fオプションと-Fオプションを併用した場合、slapd.confを使って動作し、その状態をもとにしてslapd.d配下を構築してくれる。
お。3つめがいい感じ。debianだと、/etc/default/slapdのSLAPD_CONFを空にしておくと、初期値で/etc/ldap/slapd.confを使ってくれます。また、SLAPD_CONFを設定した場合、slapd.confを与えると勝手に-fオプションで、slapd.dを与えると勝手に-Fオプションで起動してくれるようです。
ただ、3つめをやるには、上記の「SLAPD_CONFが空の場合」のロジックに乗っかりつつ、SLAPD_OPTIONSで「-F /etc/ldap/slapd.d」とするのが良さそう。ひとまずは下記のような感じで起動してみましょう。

vi /etc/default/slapd
SLAPD_CONF=
SLAPD_OPTIONS="-F /etc/ldap/slapd.d"

ちゃんと起動したようです。

 4195 ?        Ssl    0:00 /usr/sbin/slapd -g openldap -u openldap -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d

この状態になったはいいけど.....まだslapd.confから離れられない。。。そもそもcn=configのツリーはどうやって見るんだ??

で、いろいろ調べてみた結果、下記のpostが参考になりました。

http://serverfault.com/questions/272125/how-do-i-install-a-new-schema-for-openldap-on-debian-5-with-dynamic-config-cn-ba

「slapd.d/cn=config/olcDatabase{0}=config.ldif にolcRootPWを追加して起動しろ」って言ってますね。やってみました。

vi slapd.d/cn=config/olcDatabase{0}=config.ldif
olcRootPW: haraheriherihara

/etc/init.d/slapd restart

ちゃんと読めました!!!やっとconfigがいじれるようになりました!!!




で、この記事を書きながら当初のAdministrator's Guideを読み直していると、こんな記述が。。。。。

5.4. Converting old style slapd.conf(5) file to cn=config format

Before converting to the cn=config format you should make sure that the config backend is properly configured in your existing config file. While the config backend is always present inside slapd, by default it is only accessible by its rootDN, and there are no default credentials assigned so unless you explicitly configure a means to authenticate to it, it will be unusable.

cn=configフォーマットへの変換を行う前に、既存の適切な設定ファイルに対してconfigバックエンドの設定をする必要があります。configバックエンドはslapdの内部で常に存在していますが、初期設定ではrootDNでしかアクセスできず、初期クレデンシャルもないため、明示的に設定しない限り利用できません。

If you do not already have a database config section, add something like this to the end of slapd.conf
database config
rootpw VerySecret


利用中の設定ファイルにまだdatabase configセクションを追加していないなら、下記のような行をslapd.confの末尾に追加してみてください。
database config
rootpw VerySecret

な、なんだってー!ちゃんと移行方法が書いてあるじゃないか!
というわけで試してみました。
  
lennyで新規にslapdを導入すると、2.4ベースではあるものの、設定パターンは2.3を踏襲するため、slapd.confベースになっています。この状態から、適当にいくつかエントリを作成し、slapcatでも見えることを確認しておきます。エントリの作成にはphpLdapAdminを使いました。検証用のエントリなので手抜きも重要。
apt-get -y install slapd phpldapadmin
slapcat

つづいて、設定の移行をしてみます。slapd.dディレクトリ自体は作らないとダメなんですね。
/etc/init.d/slapd stop
mkdir /etc/ldap/slapd.d
chown openldap:openldap /etc/ldap/slapd.d
chmod 700 /etc/ldap/slapd.d
echo database config &gt;&gt;etc/ldap/slapd.conf
echo -n "rootpw " &gt;&gt;/etc/ldap/slapd.conf
slappasswd &gt;&gt;/etc/ldap/slapd.conf
New password:
Re-enter new password:

そして起動。ちゃんとslapd.d配下に設定が展開されているのが確認できます。
/etc/init.d/slapd start

この状態でldapsearchを実行。ちゃんと見えましたね。
ldapsearch -x -w haraheriherihara -D cn=config -b cn=config -s base
Enter LDAP Password:

ここまでくればしめたもんです。slapd.confからslapd.dへの完全移行の後始末をしましょう。
mv /etc/ldap/slapd.conf /etc/ldap/slapd.conf.old
vi /etc/default/slapd
SLAPD_CONF=/etc/ldap/slapd.d
SLAPD_OPTIONS=""
/etc/init.d/slapd restart

ちゃんと動きましたか?

2011/07/04

PHPでpost_max_size以上のデータを投げても何とかハンドリングしたい

最近phpコードを書いているんですが、post_max_size以上のデータを受け取ると

PHP Warning: POST Content-Length of 9456137 bytes exceeds the limit of 8388608 bytes in Unknown on line 0

なんてエラーを吐いてくれてエラーチェックができないんです。
対策はいくつか考えたんですが、
apacheのLimitRequestBodyを使う
コンテンツを配置するたびにapacheの設定を書くのが面倒だし確実に忘れる。AllowOverrideも環境依存だし。。
javascriptで制御
所詮クライアントサイドの気休めでしかないので信頼性低い。
MAX_UPLOAD_SIZEをhiddenで埋め込む
これも気休め。
と、どれもイマイチ決定打に欠けます。

実際にpost_max_size以上のデータを受け取ったとき、$_POSTのデータが破壊されるのか変数として提供することをあきらめるのかはわかりませんが、$_POSTの中身が空になるので、これを検知しちゃえばいいんじゃね?
ということで、意図的にエラーを発生させて観察してみました。その結果、post_max_size以上のデータを受け取ると、$_POST、$_FILESの両方とも、isset()にかけるとtrueが返されますがcount()で見ると空っぽなんですね。
これを受けて、下記のようなコードで逃げてみました。

// max_post_size越えのデータを受信した場合の対策
if(count($_POST) == 0 && count($_FILES) == 0)
{
死に際のエラー処理
exit();
}

本来はPHP側が正しくハンドリングしてくれればいいんですが、どうもこの辺のチェックが甘いようで、逃げの手法だということは知りつつもこの方法で決定。期待した動作になりました。

ちなみに、cent5系でふつうにインストールされるrpmなphpです。

# php -v
PHP 5.1.6 (cli) (built: Mar 31 2010 02:44:37)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies

2011/03/30

iTunesの"牛丼肉抜き"

(複数所有している)どのパソコンでもiPhoneは認識させたいけど、iTunesのデータは特定のマシンにしか入れていない方へ。
iTunesデータを持たせていないPCでiPhoneを充電したりすると、期待もしてないiTunesが上がってきたりしてジャマだったりしませんか?
人のiPhoneを挿したら同期が始まって慌てて止めてたりしませんか?

そんな時におススメなのが「iTunesの"牛丼肉抜き"」。
「ドライバやbonjourは入ってるけどiTunesは入ってない」状態を作ることで、iPhoneとして認識はするけどiTunesに反応しないPCにすることができます。
やりかたは簡単。
一度iTunesをインストールした後で、「iTunesだけをアンインストール」するんです。

iTunesをインストールすると、下記のものがまとめてインストールされます。
・Apple Application Support
・Apple Mobile Device Support
・Apple Software Update
・Bonjour
・iTunes
・QuickTime
なので、ここから「iTunes」だけをアンインストールすると、他のパッケージが残るというカラクリ。

Apple Mobile Device Supportは、iPhoneを使う時のWindows向けドライバを持っているので、本当に最小であればそれだけ残して後は削除、というのもありですが、自分のパソコンでは上記からiTunesを抜いただけになっています。

あ、共有パソコンだと肉抜きは難しいかもしれませんね。

2011/01/15

Intel Active Management Technologyを使ってみた

kvmの実験用に購入したIntelのDQ45CBですが、搭載されているQ45チップセットがvProに対応しています。このvProを使用することで、外出先からパソコンの電源制御やBIOS操作ができるとあるので、試してみることにしました。
今回試すのは、Intel Management Engineを設定し、外部から電源制御を行えるようにすることです。


では、まずハードウェア側の準備から始めましょう。やることは下記の3つです。
(1)Management Engineを有効にする(現在の設定が無効になっている場合)
(2)パスワードの設定
初期パスワードが設定されていますが、初期パスワードはみんな書くのを遠慮しているので、自分で調べるか知っている人(最終的にはIntelの人?)に聞いてみて下さい。ちなみに、今回は自分自身で調べてみました。調べると出てくるものです。また、パスワードの強度についてですが、(1)英字/数字/記号を含む、(2)8文字以上であること、が条件なので、忘れないようにしましょうね!
(3)ネットワーク設定
DHCPのままでも後で見つけられるのですが、安定的な管理のためには固定IPにした方が良いでしょう。あと、外部から接続するときのためにゲートウェイは忘れずに! LAN内からしか繋がないのなら、少し歩いて自分で電源ボタン押しにいけばいいでしょ(ぉ
(4)その他の設定
ある場合とない場合があるので、都度説明します。

では具体的な手順についてです。

F2を押してBIOSに入り、メニューから「Intel(R) ME」を選択しましょう。
設定画面に入るときにパスワードを設定します。
パスワードの設定が終わると、メニューに入れるようになります。

続いて、「Intel(R) Active Management Technology Configuration」のメニューからネットワークを設定します。
追加の設定ですが、プロビジョニングの設定を行いましょう。
同じ階層に「Provisioning Configuration」というメニューがあります。
「Enterprise」となっているところを、「Small-Medium Business」に変えておきます。
この状態でBIOSを保存しましょう。

ここまでできたら、ハードウェア側の準備は完了です。
あとのお楽しみのために、一度電源を落としておきましょう。

続いて、Intel AMT Developer Tool Kitを以下のURLからダウンロードします。

Download the latest version of Manageability Developer Tool Kit
http://software.intel.com/en-us/articles/download-the-latest-version-of-manageability-developer-tool-kit

ダウンロードしたMSIをインストールすると、下記の3つのプログラムが入ります。
・Manageability Commader Tool
・Manageability Connector Tool
・Manageability Outpost Tool
ここでは、このうち"Manageability Commader Tool"というプログラムを利用します。


で、起動したのがこの画面。


さっき登録したIPアドレスとパスワードを利用して、このツールに登録します。
IPアドレスをDHCPで取得させる場合は接続先IPが分からないので、DHCPのスコープを入力してStartを押しましょう。
たぶん出てきます(笑)


追加が完了したら、左ペインに現れたマシンをクリックすると、右ペインが「Connect & Control」というウィンドウに変わります。
さっそく接続してみましょう。Connectボタンを押してみます。


つながったよ兄さん!!


さっそくツリーの中を見てみます。資産情報からハードウェア情報までちゃんと見えてます。


さて、今回のお目当て、リモート制御機能です。
タブを「Remote Control」に切り替えます。


そこに現れた「Take Control」というボタンを押すと、Serial Over LANで画面制御ができるようになります。
画面を良くみると、「IDE Redirect」という項目が表示されており、その脇にイメージファイルが指定されていることから、
うまく使えばリモートでのインストールだってできそうですね。


とりあえず立ち上げてみましょう。
「Remote Command」のメニューから「Remote Reboot to BIOS Setup」を選んでみます。
なぜ普通に起動しないかって?そりゃ一番分かりやすいからですよ(笑)
右上に表示されていた状態がSoft off(S5)からFull Power(S0)に変わり、しばらく待つとちゃんとBIOSの画面になりました。
Serial over LANなので、画面レンダリングが昔のパソコン通信を見ているようです。

外出先から自宅にVPNが張れれば、あとはほぼ思いのままです。

2010/12/24

Thunderbirdがすごい。だけど.....

少し前にうちのメールをIMAP化し、昔使っていた別のメールクライアントのメールを取り込むべくインポートをやっていたわけなんですが、 Thunderbird、すごいですね。メールボックスをまたいでメッセージを移動できるし、移動元がPOPで移動先がIMAPだとアップロードまでしてくれます。これで、iPhoneからでも会社からでも自分の家でも全部同じメールが見られる~

と思っていたら、どうもメールの表示順序がおかしいのです。メールヘッダにあるタイムスタンプは確かに維持されているんだけど、表示順序が「Thunderbirdに取り込まれた順」になっている。昨日のメールよりも新しい位置にインポートしたメールがあるわけで、iPhoneで見るときに「最新の100通」を見るとインポートしたメールで埋まってる.....これでは使い物になりません。

で、調べてみると、IMAPサーバに保存されているメッセージのファイル名が「インポートしたときのUNIX秒」になっているっぽい.....これを直せばどうにかなるかな。

というわけで、こんなスクリプトを組みます。要は、各メッセージのファイル名に入っているUNIX秒を、Dateヘッダが示すUNIX秒に差し替えてリネームするわけです。


#!/bin/sh

cd ~
for dir in `find ~/Maildir -type d -name cur`; do
cd $dir
pwd
for file in `ls`; do
dater="`grep ^Date: $file | head -1 | sed -e 's/^Date://; s/ (JST)$//; s/Thr/Thu/'`"
dates=`date -d "$dater" +%s`
new=`echo $dates@$file | sed -e 's/@[1-9][0-9]*\././'`
echo -n "$file -> $new : "
if [ "$file" = "$new" ]; then
echo not renamed.
else
mv -i $file $new
echo renamed.
fi
done
done


コツをいくつか。
・Maildir形式での各メッセージは確実にユニークなファイル名を持つようになっているので、1ファイルずつ処理できます。ファイル名の命名規則については下記で解説されています。
http://cr.yp.to/proto/maildir.html
・head -1が入っているのは、マルチパートのメールとかだとDateヘッダが複数入っているので、一番最初のだけを持ってくる必要があるからです。他の言語を使えばオブジェクトで扱えるのですが、そこまでは要求していないのでこれで十分。
・ThrをThuに変えているのは、dateコマンドのフォーマットとして認識してくれないからです。メールソフトの中には、木曜日の短縮形をThuではなくThrで記述するものもあるみたいですね。

もちろんここにくるまでにちゃんとデバッグしてますよ。mvだけコメントアウトしておけば何度でもプレビューできるので便利です。ついでに、テスト実行時には標準出力「だけ」を捨てておくと、エラーの有無がわかりやすくて便利です。こういうとき、標準エラー出力って便利だな、と思います。

で、imapのサービスを止めて、いざ実行!

Thunderbirdを立ち上げてみると....お!うまくいってる!
しかしログにこんな記述が!
「△△△フォルダから0000通のメールを削除しました」....えええ!!!!

よく見ると、ローカルのメール(実質的なキャッシュ)をリモートフォルダ(つまりIMAP上のオリジナルメール)に合わせている挙動でした。リモートのメールが消されているものと勘違い(汗

改めてiPhoneから見てみたところ、期待したとおりに表示されているようです。