プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

コマンドラインツールの認証をIAMに切り替える

現在、Redmineを運用しているEC2のサーバーですが、ちょっと昔に運用を開始したので、EC2のコマンドラインツール利用時の認証がIAMではなく、いまでいうルートアクセスキーでの認証になっていました。当時はIAMなんてなかったですね。せっかくなので、IAMユーザーを作成して、こちらで認証するように切り替えてみましたので、作業時のメモを残しておきます。

なお、このサーバー上で、ルートアクセスキーを使っている作業は、下記のものになります。

先頭から3つがEC2のコマンドラインツールで、最後の一つがS3(s3cmd)ですので、両方の認証をIAMに切り替えます。

 

(参考) IAMへの移行に関して参考になりそうな記事がいくつかあったので、載せておきます。

 

EC2コマンドラインツールの認証をIAMに切り替え

作業前に、EC2コマンドラインツールの説明を確認すると、X.509証明書を使う方法が見当たりません。環境変数の設定方法も以前とは異なっているようです(以前は、EC2_PRIVATE, EC2_CERT を設定していたのが、AWS_ACCESS_KEY, AWS_SECRET_KEY を設定するようになってます)。少し、ネットを検索してみると、『EC2 API ToolsでアクセスキーIDとシークレットアクセスキーを使う』というブログ記事がありました。こちらを見ると、IAMユーザー用に作成したアクセスキーとシークレットアクセスキーを使えば、問題なく繋がりそうです。

では、実際にやってみます。

IAMユーザーの作成

IAMユーザーを作成します。『管理コンソール』から『IAM』を選択し、『ユーザー』の『新規ユーザーの追加』ボタンを押します。あとは、画面の指示に従って作れば問題ありません。

ユーザー作成後に、アクセスキーとシークレットアクセスキーが表示(およびCSV形式でのダウンロード)されるので、大切に保管しておきます。

作成したユーザーに対して、『ユーザー』→ユーザー名を選択→アクセス許可→『管理ポリシー』→『ポリシーのアタッチ』ボタンを押します。

このユーザーに割り当てる権限の一覧が表示覚ます。今回は、EC2での作業を行いたいので、『AmazonEC2FullAccess』を選択しておきます。

 

同様に、もう一名S3へのアクセス用のユーザーを作成します。ポリシーは、『AmazonS3FullAccess』としておきます。

 

EC2コマンドラインツールの認証情報の切り替え

やってみると、難しい話ではなく、EC2コマンドライン実行時の環境変数として、

# keys
export AWS_ACCESS_KEY=xxxxxxxx
export AWS_SECRET_KEY=xxxxxxxx

を追加するだけです(EC2作業呼び出し用の設定ファイルを書き換えてます)。

 設定後、コマンドラインから、

bitnami@ip-10-132-170-91:~$ ec2ver
1.6.5.2 2012-10-01
bitnami@ip-10-132-170-91:~$ 

 として、正しく認証されていることを確認します。

 

次に、実際にコマンドを呼び出しているところの認証情報の与え方を修正します。以前は、

ec2-create-snapshot --private-key ${EC2_PRIVATE_KEY} --cert ${EC2_CERT} --description "説明" ebs_vol番号

 と与えていたところを

ec2-create-snapshot --aws-access-key ${AWS_ACCESS_KEY} --aws-secret-key ${AWS_SECRET_KEY} --description "説明" ebs_vol番号

 のように修正します。

 

S3(s3cmd)の認証情報の切り替え

こちらの認証情報の切り替えも簡単です。s3cmd の初期設定を呼び出せばOKです。ただし、利用するIAM認証情報は、S3アクセス用のユーザーに対するアクセスキーとシークレットアクセスキーになります。

bitnami@ip-10-132-170-91:~$ s3cmd --configure

Enter new values or accept defaults in brackets with Enter.
Refer to user manual for detailed description of all options.

Access key and Secret key are your identifiers for Amazon S3
Access Key [old_xxxxxxxx]: new_xxxxxxxx
Secret Key [old_yyyyyyyy]: new_yyyyyyyy

Encryption password is used to protect your files from reading
by unauthorized persons while in transfer to S3
Encryption password [xxxxxxxx]: 
Path to GPG program [/usr/bin/gpg]: 

When using secure HTTPS protocol all communication with Amazon S3
servers is protected from 3rd party eavesdropping. This method is
slower than plain HTTP and can't be used if you're behind a proxy
Use HTTPS protocol [Yes]: 

New settings:
  Access Key: new_xxxxxxxx
  Secret Key: new_yyyyyyyy
  Encryption password: xxxxxxxx
  Path to GPG program: /usr/bin/gpg
  Use HTTPS protocol: True
  HTTP Proxy server name: 
  HTTP Proxy server port: 0

Test access with supplied credentials? [Y/n] y
Please wait...
Success. Your access key and secret key worked fine :-)

Now verifying that encryption works...
Success. Encryption and decryption worked fine :-)

Save settings? [y/N] y
Configuration saved to '/home/bitnami/.s3cfg'
bitnami@ip-10-132-170-91:~$ 

 これで、S3へも問題なく接続できるようになりました。

 

ルートアクセスキーの削除

これで、問題なく動作すると思いますので、一通り設定した機能が問題なく動作することを確認しておきます。

問題なかったので、ルートアクセスキーとX.509証明書を削除します。

これで、IAMユーザーへの切り替えが完了しました。

 

余談

まったくの余談になるのですが、SecurityGroupの設定で、自宅のIPアドレスからのアクセスに制限しているのですが、この設定の自動更新を確認するため、自宅のルーターの電源を一旦切って再度いれなおしたところ、DDNSの更新が反映されるのに2時間ぐらいかかってました。こんなにかかるものなんでしたっけ?

s3fsが予期せずアンマウントされた場合への対策

[s3] s3 をファイルシステムとしてマウントする で書いたように、s3fs を利用し始めたのですが、@kazuyuki さんから突然マウントが切れることがあるよ、との情報を頂きました。

今のところ、手元の環境ではこのような現象は発生していないのですが、マウントが切れると困るので簡単な対策をしておきます。やりたいことは、マウントが切れた際にメールで教えてくれるのと、自動で再マウントをするというものです。

環境は次のとおりです。

OS:Ubuntu 14.04.1 LTS, 64bit (EC2)

s3fs-fuse:v1.78

 

メール送信のための準備

今回s3fsを試しているサーバー(EC2上)には、メール送信環境がないので、まずはこれを作っておきます。

ローカル環境の状態についての通知を出すだけなので、sendmail/postfixなどのMTA(Mail Transfer Agent)を使うのではなく、メール送信だけに使えるsSMTPを使います(MSP, Mail Submission Program)。MTAやMSPについては下記の参考サイトなどをご覧ください。

 

(参考)

Ubuntu 12.04 でメールサーバを立てずに sSMTP で CRON メールを送信するには

sendmail 8.12とMILTER (FreeBSD PRESS No.8) この『2. 8.12のインストールと設定』にある図が、MTA,MSP等の関係を分かりやすく示してくれています。

 

まず、必要なプログラムをインストールします。

ubuntu@ip-172-31-9-233:~$ sudo apt-get install ssmtp
ubuntu@ip-172-31-9-233:~$ sudo apt-get install mailutils

mailutils はメール送受信用のクライアントプログラムですね。

設定は下記の参考サイトなどを参照して、次のようにしておきます。なお、ここで利用している既存のSMTPサーバーは自分が契約しているさくらインターネットのサーバーになります。

/etc/ssmtp/ssmtp.conf

#
# Config file for sSMTP sendmail
#
# The person who gets all mail for userids < 1000
# Make this empty to disable rewriting.
root=postmaster

# The place where the mail goes. The actual machine name is required no 
# MX records are consulted. Commonly mailhosts are named mail.domain.com
mailhub=さくらインターネットのSMTPサーバー:587

# Where will the mail seem to come from?
#rewriteDomain=

# The full hostname
#hostname=ip-172-31-9-233.ap-northeast-1.compute.internal
hostname=ホスト名

# Are users allowed to set their own From: address?
# YES - Allow the user to specify their own From: address
# NO - Use the system generated From: address
#FromLineOverride=YES

# added for SMTP auth
AuthUser=ユーザー名
AuthPass=パスワード
AuthMethod=cram-md5

(参考)

sSMTP でメールを送信できるようにする

 

なお、上記の設定では、サブミッションポート(587番)の設定とSMTP認証を行っています。

 

設定が終わったら、メールの送信テストを行います。

ubuntu@ip-172-31-9-233:~$ echo test mail | mail test@domainname

設定に問題がなければ、メールが届いていると思います。ちなみに、Ubuntuの場合、mailコマンドで送信する場合は、.(ピリオド)で本文の入力が終わるのではなく、Ctrl+Dで終了となるそうです。

https://forums.ubuntulinux.jp/viewtopic.php?id=12176

 

なお、最初設定したとき、hostname にEC2のプライベートIPに対するホスト名が設定されていました。このままでメールの送信を行うと、送信者のアドレスのドメイン名が不明だといわれて、送信に失敗してしまいます。なので、ホスト名にはDNSで解決できる名前にするか、パブリックIPアドレスにする必要がありそうです。

 

マウントの確認

こちらのStackOverFlow記事を参考に、s3のバケット内に空ファイルを作成しておき、これをlsで確認して、確認できなかったら、マウントが切れたと判断します。

チェック用のスクリプト(/etc/s3fs/check_mounts3)はこんな感じです。

#!/bin/sh
#
# check mount s3 via s3fs and remount if mount is broken
#
# Junichi MORI, 2015/6/16

# need for english error message
LANG=C

MOUNT=/etc/s3fs/mounts3
#target file
MOUNT_PT=/mnt/s3fs
TARGET=${MOUNT_PT}/s3fs_exist

# check, whether a target file is exist or not
ls ${TARGET} > /dev/null 2>&1
if [ 0 = $? ]
then
  echo `date --rfc-2822` ": keeping mount s3 via s3fs"
  return 0
else
  echo `date --rfc-2822` ": unexpected umount s3" 1>&2

  # try re-mount
  echo "try re-mount s3fs..." 1>&2
  umount ${MOUNT_PT}
  ${MOUNT}
  if [ 0 = $? ]
  then
    echo "success re-mount s3fs" 1>&2
  else
    echo "failed re-mount s3fs" 1>&2
  fi
  return 1
fi

ここで、s3fs_existというファイルがマウントチェック用のダミーの空ファイルです。

やってることは、s3fs_existファイルをlsで呼び出し、正常終了ならそれまで、異常終了なら、マウントが外れていると判断し再マウントを行う、というだけのものです。なお、マウントが外れた場合はメールで知りたいので、すべて標準エラー出力へ出すようにしています。

チェック用のスクリプト内で呼び出している /etc/s3fs/mounts3 というコマンドは、[s3] s3 をファイルシステムとしてマウントする で書いたrc.localの内容を独立させたもので、s3fsを使ってマウントを実行する内容になっています。こちらも一応載せておきます。

#!/bin/sh
#
# mount s3 via s3fs
#
# Junichi MORI, 2015/6/16

BUCKET=バケット名
FOLDER=フォルダ名
MOUNT_PT=/mnt/s3fs
CACHE_DIR=/tmp

S3FS_OPTION="-o allow_other -o use_cache=${CACHE_DIR}"

#umount /mnt/s3fs
/usr/bin/s3fs ${BUCKET}:${FOLDER} ${MOUNT_PT} ${S3FS_OPTION}

これらのスクリプトが正しく動作しているかコマンドラインから起動して確認しておきます。 

cronからの呼び出し

ここまでくれば、これらをcronから呼び出せば、OKです。

Ubuntuの場合、/etc/cron.dに呼び出すコマンドをcrontab形式で書けばOKです。

# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

MAILTO=メールアドレス
# m h dom mon dow user  command
4 *     * * *   root    /etc/s3fs/check_mounts3 1> /dev/null
#

マウントが切れた場合は、標準エラー出力に何かしら出力されるので、その出力内容がメールで飛ばされるという次第です。マウントが切れていない場合は何も出力されないのでメールは飛びません。

コマンドラインからマウントを切って、cronが実行される時間になると、マウントエラーが発生した旨のメールが飛んできて、再マウントもされていました。いい感じです。

当面、これで監視しながら様子を伺うことにします。

 

参考

このほかに使えそうな対策としては、autofs を使いリクエストがあった場合に自動的にマウントするという方法がありました(下記、参考記事の目的はちょっと異なりますが)。場合によってはこの方法のほうが好都合がかもしれません。マウントが切れるという不具合が頻発するようになったら考えてみようと思います。

(参考)

autofsでs3fsを利用する

 

履歴

 2015/9/13 ssmtp と mailutils のインストールの順番を間違えていたので、修正した

s3 をファイルシステムとしてマウントする

EC2を使っていると、EC2のインスタンスのディスク容量はインスタンス作成時に決めていることもあり、s3 をストレージとして利用したくなります。S3上のファイルやフォルダがEC2インスタンス側からファイルシステムとして扱えれば、こんなに嬉しいことはありません。今回、これを実現するために、 s3fs-fuse を導入し、その設定を行ったので、メモ書きとして残しておきます。この記事では、ローカルPC(VM)上に導入したときの手順を元に書いてますが、EC2上でも変わりありません。

 

OS:Ubuntu 14.04.1 LTS, 64bit

s3fs-fuse:v1.78

 

まあ、将来的には、EFSが導入されれば、こんなことしなくても良いのかもしれませんが。

【AWS発表】Amazon Elastic File System (EFS) - Amazon EC2 のための共有ファイルストレージ

 

s3fs-fuseのインストール

s3fs-fuse はFUSE (Filesystem in Userspace) の機能を利用して、s3をファイルシステムのように扱うためのものです。FUSEそのものについては参考記事などを参照してください。

s3をファイルシステムとして使うにはこれをインストールします。

インストール方法は、特に難しいわけでもなく、 Tested on Ubuntu 14.04 LTS に記載されているとおりに実行すればOKです。ただし、今回は、最後の

sudo make install

 の代わりに

sudo checkinstall

 として、パッケージ化してインストールを行いました。

checkinstall はソースコードからmake, make install などとしてインストールする場合に、一旦パッケージを作成して、それをインストールするというものです。これ便利ですよね。詳しくは、 Wikipediaの記事などを参考にしてください。

 

s3fsの設定

では早速設定してみましょう。設定もそんなに難しい話ではありません。最初は、AWS側での作業です。

 

AWSでの作業

S3へのアクセスのみを許可したIAM ユーザーを作成します。

IAM の理解としては、個別に操作権限を割り当てたユーザーを作成し、それを使ってアクセスすることで、仮に不正アクセスが発生しても、権限を与えられた範囲外へ被害が及ぶのを防ぐという仕組みだと思っています(違っていたらごめんなさい)。余計な料金もかからないし、積極的に利用したいところです。まあ、そんな大仰なこと言い出さなくても、必要最小限の権限で処理を行うというのはなんにでも通用する考えですしね。

IAMユーザーを作成したら、アクセスキーIDとシークレットアクセスキーを控えておきます。

あと、S3上にバケットを作成しておきます。必要があればフォルダも作っておきます。

 

PC側での作業

次は、S3をマウントするPC側での作業になります。

 

まず、S3にアクセスする際の認証情報を、/etc/passwd-s3fs に記述しておきます。ここなどを参考にしてください。

https://github.com/s3fs-fuse/s3fs-fuse/wiki/Fuse-Over-Amazon

書式は、バケット名:アクセスキー:シークレットキー となります(バケット名はなくてもかまいません)。

mor@ubuntu:~$ sudo cat /etc/passwd-s3fs 
バケット名:アクセスキーID:シークレットアクセスキー
mor@ubuntu:~$ 

このファイルのパーミッションを変更しておきます。

sudo chmod 640 /etc/passwd-s3fs

マウントポイントを作成します。

sudo mkdir /mnt/s3fs

 コマンドラインからマウントしてみます。

sudo s3fs バケット名:/フォルダ名 /mnt/s3fs -o allow_other -o use_cache=/tmp

 ここで、オプションは、

  • allow_other: root 以外(マウントしたユーザー以外)も利用可能とする
  • use_cache: 指定したフォルダを読み出し用のキャッシュフォルダとして使用

のような意味です。

マウントできたことを確認します。

mor@ubuntu:~$ mount
/dev/sda1 on / type ext4 (rw,errors=remount-ro)

s3fs on /mnt/s3fs type fuse.s3fs (rw,nosuid,nodev,allow_other)

mor@ubuntu:~$ 

のようにマウントできていることが分かります(df -hでも確認できると思います)。

 

実際にマウントポイントを見てみると、

mor@ubuntu:~$ ls -l /mnt/
合計 8
drwxr-xr-x 2 root root 4096  94  2014 hgfs
drwxr-xr-x 2 root root 4096  69 00:29 s3fs
mor@ubuntu:~$ 

 だったのが、

mor@ubuntu:~$ ls -l /mnt
合計 5
drwxr-xr-x 2 root root 4096  94  2014 hgfs
drwxrwxrwx 1 root root    0  11  1970 s3fs
mor@ubuntu:~$ ls -l /mnt/s3fs/
合計 1
drwxrwxr-x 1 mor mor 0  428 22:40 store
mor@ubuntu:~$ 

 のように見えてます(storeというフォルダはs3上に作ってあるフォルダです)。

 

起動時にマウントするための設定

これで問題なくマウントできるようになったので、起動時に自動的にマウントする設定にしてみます。ググると、/etc/fstab に記述すればよいというのが多かったのですが、なぜか手元の環境ではうまくマウントできませんでした。

そこで、今回は、/etc/rc.localにマウントするためのコマンドを記入することで対応しました。

mor@ubuntu:~$ cat /etc/rc.local
#!/bin/sh -e
#
# rc.local

# s3fs mount
#umount /mnt/s3fs
s3fs omikujips:/test /mnt/s3fs -o allow_other -o use_cache=/tmp

exit 0
mor@ubuntu:~$ 

これで、再起動しても、s3がマウントされるようになりました。便利ですねー。

 

参考

FUSEについて

FUSE Wikipedia

FUSEとはIT Pro

 

S3FSよりAPIのほうがよい?

S3FSよりもAPIでアクセスするほうがよいとの指摘もあります。

http://blog.genies.jp/2011/08/amazon-ec2-amazon-linux-s3.html

 

今回はS3から読み出したファイルをPC上でローカルファイルとして扱いたかったので、s3fsを使ってみました。

これをAPIでやろうとすると、s3から読み出したファイルを一旦ローカルに作成しないといけないかと思います。で、今回の目的のものでは、s3上のファイルサイズが大きく、またアクセスする必要があるファイル数も多いので、これを自前でやろうとするとファイルキャッシュを自分で用意する必要が出てきそうで、今回はやめました。

一方、s3fsの場合だと、use_cacheオプションを有効にしておいて、あとは適当なタイミングでキャッシュをクリアするようにすれば済みそうです。

(もろもろ理解が違ってたら、すいません)

実際のところはどうなんでしょうか?

 

s3fsの速度について

ローカルのPC上にs3fsを設定して、読み書きしてみると、まあ遅いこと遅いこと。ネットワーク経由なので、仕方ないですね。

同じリージョン内で、EC2のインスタンスからs3fs経由でs3にアクセスするとこちらは、まあ、耐えられなくはない速度でした。とはいうものの、目的次第ではやはり遅いかと思いますので、一度自分で試してみることが大事そうだなと感じてます。

 

fstabへの記述でうまく起動時にマウントできない現象について

リブート前にアンマウントしていない場合、マウントできないことがあるという記事がありました。
http://kumachan.biz/2014/11/10_2258/4228/
https://angelndxp.wordpress.com/2014/03/06/%E3%80%90aws%E3%80%91-s3fs%E3%83%9E%E3%82%A6%E3%83%B3%E3%83%88%E6%99%82%E3%81%AB%E8%B5%B7%E3%81%93%E3%82%8B%E5%95%8F%E9%A1%8C%E3%81%A8%E3%80%81%E3%81%9D%E3%81%AE%E5%9B%9E%E9%81%BF%E6%96%B9%E6%B3%95/

でも、残念ながら、事前にアンマウントしていても同じことが発生していたので、ちょっと真の原因はアンマウントではないかも。

ちなみに、これらの記事の方法を試そうとしたら、この場合、fstabとrc.localの両方に記述する必要がありました。
(rc.local への記述だけだとマウントがなくて、umountコマンドを呼び出すと、失敗になるため正しくマウントされませんでした)


似たようなissueもあるそうだ。
https://code.google.com/p/s3fs/issues/detail?id=300
https://code.google.com/p/s3fs/issues/detail?id=317

これらに記載の対応方法を取れば良さそうですが、今回は見送りました。