toto_1212

技術のログをツラツラ書きます。自分用ですが参考にしていただけたら嬉しいです。間違ってたらドンドン突っ込んでください。

【CloudFront】署名付きURL(Signed URL)をOpenSSLで作成

署名付きURLとはCloudFront経由のコンテンツへのアクセス元を限定したり、公開期限を指定したり、セキュアにプライペートなコンテンツを公開する機能です。


署名付き URL の概要 - Amazon CloudFront

実現するにはCloudFrontキーを作成し、作成したポリシーをエンコードし、更に署名化し、URLとそれらいくつかの情報をくっつけてアクセスするためのURLを作成します。
エンコード/署名にはいくつか方法があり、perlPHPC#、.NET、JAVA、OpenSSL等があります。今回はSDKが使えなくてもOpenSSLで簡単に出来るのでその方法を書きたいと思います。

署名付きURLには2通りの種類があり、1つのオブジェクトへの制限・停止する日時を指定できる「既定ポリシー」と1つ以上のオブジェクトへの制限・停止する日時・アクセスできるIPを制限できる「カスタムポリシー」があります。
今回は接続元も制限できるカスタムポリシーで制限をかけてみます。

・テスト用webサイト構築するためテスト用のインスタンスにwebサーバを立てる。

・純粋にEC2へ直接アクセスし、webページが表示されることを確認する。
f:id:toatoshi:20141201233508j:plain

・CloudFrontを受け入れるセキュリティグループを作成し作成したインスタンスに適用する。
 CloudFrontのエッジサーバが利用するIPレンジが決まっているので、そのIPアドレスを設定する。

CloudFront エッジサーバーの場所と IP アドレス範囲 - Amazon CloudFront

・CloudFrontのディストリビューションを作成し、オリジンをテスト用インスタンスに向ける。

・CloudfrontのDomainNameでアクセスし、webページが表示されることを確認する。
f:id:toatoshi:20141202000057j:plain

・managementコンソールのSecurity CredentialsよりCloudFront Key Pairsにて鍵を生成し、private key ファイルをダウンロードするf:id:toatoshi:20141202085002j:plain

・作成したCloudFrontのBehaviors設定からSignedURLを有効にするためRestrict Viewer Access
 YESにする(作成済みのもでも設定可能)
 別アカウントのCloudfrontキーを利用する場合はTrusted SignersをSpecify Accountsにし
 対象のアカウント番号を入力する。
f:id:toatoshi:20141201233939j:plain

・ポリシーが設定されていないため、制限がかかっていて閲覧できないことを確認する。
f:id:toatoshi:20141202000432j:plain

・OpenSSLがインストールされているサーバを用意する。
 EC2でもオンプレのどちらでもよいが、この手順ではAmazonLinuxを使っている。

・ダウンロードしたprivate keyを用意したサーバの/tmpへアップロードする。

・/tmpにpolicyという名前でポリシーを記載したファイルを作成する。

☆今回のポリシーは、対象サイトへの接続は自宅のグローバルIPのみとし、
 2014/11/30 23:00:00まで接続可能とする。
 接続できる時間(DareLessThan)の記載は必須項目となり、時間はUnixTimeでの記載となる
 UnixTimeへの変換はUNIXTIME相互変換ツール - konisimpleを使うと楽チン。

#サンプルポリシー
{
"Statement": [{
"Resource":"http://xxxxxxxxxxxxxx.cloudfront.net/*",
"Condition":{
"IpAddress":{"AWS:SourceIp":"xxx.xxx.xxx.xxx/32"},
"DateLessThan":{"AWS:EpochTime":1417356000}
}
}]
}

・policyをBase64エンコードする

$ cat policy | openssl base64 | tr '+=/' '-_~'

☆返り値
eyAKICAgIlN0YXRlbWVudCI6IFt7IAogICAgICAiUmVzb3VyY2UiOiJodHRwOi8v
ZDIyMGR6dWl3ZHF3OXouY2xvdWRmcm9udC5uZXQvKiIsIAogICAgICAiQ29uZGl0
aW9uIjp7IAogICAgICAgICAiSXBBZGRyZXNzIjp7IkFXUzpTb3VyY2VJcCI6IjEy
MS4xMDIuMTcuMjMyLzMyIn0sIAogICAgICAgICAiRGF0ZUxlc3NUaGFuIjp7IkFX
UzpFcG9jaFRpbWUiOjE0MTczNTYwMDB9CiAgICAgIH0gCiAgIH1dIAp9Cg__

・policyを署名に変換する

$ cat policy | openssl sha1 -sign pk-APKAJKTNETSYZLRR5RJQ.pem | openssl base64 | tr '+=/' '-_~'

ZkE9khCVW70dZqe-IjsJnALOnoR1jEOLXjLXp04Nr4~oca8OQHxOAK02u1lF6Gex
OmRz3uF7naMOQz8rap8xg-MnY0ZUOgcKt~EgmC4DI6DRsGh6gaWzE5r5eOsj29Nb
zyPPGYWGx-MKgncKdSI23-7rFUOlPkAoxyFxmxZ8K~3QfjCNJHAUtwBYUVdAU3~P
37roKM1CE1QLT4do4bJpHY5eR0KFu8t0WvvqYKg1O5P5K0K27FNul~Peb~NKALmN
ggVufjVqIashKhJAh66MImEsJ~nIvk2~fzmTe1Pzt29e8JwPrwnjQkblFvIHbrLz
Ae2CDPrCqTYJAXmCLlY-jA__

・出力された情報を利用してURLを生成する

1️⃣1. 対象のサイトURLを記載(ワイルドカード可能)
  2. ?
  3. クエリ文字列パラメータ(ある場合)&
  4. Policy= ポリシーステートメント(←・policyをBase64エンコードするで生成したもの)
  5. &Signature= ハッシュ化および署名されたバージョンのポリシーステートメント(← ・policyを署名に変換するで生成したもの)
  6. &Key-Pair-Id= 作成したCloudFront キーペア ID

1 + 2 + 3 + 4 + 5 + 6のようにしてURLを作成する。

http://d220dzuiwdqw9z.cloudfront.net/?&Policy=eyAKICAgIlN0YXRlbWVudCI6IFt7IAogICAgICAiUmVzb3VyY2UiOiJodHRwOi8vZDIyMGR6dWl3ZHF3OXouY2xvdWRmcm9udC5uZXQvKiIsIAogICAgICAiQ29uZGl0aW9uIjp7IAogICAgICAgICAiSXBBZGRyZXNzIjp7IkFXUzpTb3VyY2VJcCI6IjEyMS4xMDIuMTcuMjMyLzMyIn0sIAogICAgICAgICAiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MTczNTYwMDB9CiAgICAgIH0gCiAgIH1dIAp9Cg__&Signature=ZkE9khCVW70dZqe-IjsJnALOnoR1jEOLXjLXp04Nr4~oca8OQHxOAK02u1lF6GexOmRz3uF7naMOQz8rap8xg-MnY0ZUOgcKt~EgmC4DI6DRsGh6gaWzE5r5eOsj29NbzyPPGYWGx-MKgncKdSI23-7rFUOlPkAoxyFxmxZ8K~3QfjCNJHAUtwBYUVdAU3~P37roKM1CE1QLT4do4bJpHY5eR0KFu8t0WvvqYKg1O5P5K0K27FNul~Peb~NKALmNggVufjVqIashKhJAh66MImEsJ~nIvk2~fzmTe1Pzt29e8JwPrwnjQkblFvIHbrLzAe2CDPrCqTYJAXmCLlY-jA__&Key-Pair-Id=APKAJKTNETSYZLRR5RJQ

・作成したURLでアクセスし、閲覧できることを確認する。
f:id:toatoshi:20141202000555j:plain

・設定した時間を過ぎたらアクセス出来ないことを確認する。
f:id:toatoshi:20141202000629j:plain

参考URL


署名付き URL の概要 - Amazon CloudFront


カスタムポリシーを使用して署名付き URL を作成する - Amazon CloudFront


Linux コマンドおよび OpenSSL を使用して Base64 エンコードおよび暗号化を行う - Amazon CloudFront

開発期間の無駄なコストを省く

今更ですが、今日別部署の方からお願いされたので。。。
開発中で夜間EC2が必要ない時にaws-cliで手軽に自動起動/停止する方法です。

ローカルの仮想環境で弱スペックでかまわないので最小構成のcentOSを立てます。
aws-cliを導入し、クレデンシャルファイルを設定します。

以下をcronに設定する

MAILTO=""
AWS_CONFIG_FILE=/root/aws/awscli.conf

00 21 * * 1-5 aws ec2 stop-instances --instance-ids=i-xxxxxxxx >>/tmp/cronlog.log 2>>/tmp/cronlog-err.log

00 8 * * 1-5 aws ec2 start-instances --instance-ids=i-xxxxxxxx >>/tmp/cronlog.log 2>>/tmp/cronlog-err.log

平日の8時から21時のみEC2を起動させておく設定です。
awscli.confファイルの場所や起動しておく時間、ログの出し方などは適宜変えて下さい。

コレだけでも意外にコストが下がりますのでぜひ。

【EC2】 RHEL6.5 /var/log/messageのttyS0エラー

EC2上へRHEL6.5を新規でローンチしOS初期設定を終え、CloudWatchへHDD空き容量をputすると5分毎で空き容量が200kbずつ減っていてなんかおかしいと思い調査しました。

調査してすぐに/var/log/messageにttyS0エラーが数秒に1回出ている状態。

エラーの内容は以下の通り

Oct 16 05:01:54 hostname init: ttyS0 (/dev/ttyS0) main process (13534) terminated with status 1'
Oct 16 05:01:54 hostname init: ttyS0 (/dev/ttyS0) main process ended, respawning'
Oct 16 05:01:54 hostname agetty13537: /dev/ttyS0: tcgetattr: Input/output error'
Oct 16 05:02:04 hostname init: ttyS0 (/dev/ttyS0) main process (13537) terminated with status 1'
Oct 16 05:02:04 hostname init: ttyS0 (/dev/ttyS0) main process ended, respawning'
Oct 16 05:02:04 hostname agetty13538: /dev/ttyS0: tcgetattr: Input/output error'
Oct 16 05:02:14 hostname init: ttyS0 (/dev/ttyS0) main process (13538) terminated with status 1'

ttys0なのでシリアル周りのエラーであることは確かで、シリアル通信は不要なので起動時に接続しようとする動作を止めることにする。

inittabよりagettyが起動され設定ファイルに基づき動作をしているため、設定ファイルで制御する。

/etc/init/ttyS0.conf

start on runlevel [2345]
stop on runlevel [016]
respawn
instance /dev/ttyS0
#exec /sbin/agetty ttyS0 115200 vt100-nav      #←コメントアウト

再起動後、エラーが止まる。

各種ポリシーの書き方

AWSのポリシはS3やIAMといったサービスのセキュリティ面に関して欠かせません。

記載方法がJSONで初めて書くときはかなり困惑するのかと思います。

JSON Editor Onlineのようなエディタをを使うと分かりやすいのですが、実際に書いてみると
()や[]の数が合っていなかったり、スペルミスったりとかで、エラーではじかれてせっかくの
時間が無駄に終わるなんて事もあると思います。

そこでAWS Policy Generatorで簡単に、そしてすばやく記載してしまいましょう。

書き方は簡単。
Step 1: Select Policy Typeでどのサービスのポリシを書くのかを指定し、Step 2: Add Statement(s)で動作条件を書くだけ。

例として「S3バケット(toto1212testbk)にはtoto_1212ユーザしかアクセスが許されず、且つS3アップロード時は暗号化を必須とする」を書く場合は以下の通り。

{
  "Id": "Policy1413814452383",
  "Statement": [
    {
      "Sid": "Stmt1413814421077",
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Deny",
      "Resource": "arn:aws:s3:::toto1212testbk/*",
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "AES256"
        }
      },
      "Principal": {
        "AWS": [
          "*"
        ]
      }
    },
    {
      "Sid": "Stmt1413814447632",
      "Action": "s3:*",
      "Effect": "Deny",
      "Resource": "arn:aws:s3:::toto1212testbk/*",
      "NotPrincipal": {
        "AWS": [
          "arn:aws:iam::xxxxxxxxxxxx:user/toto_1212"
        ]
      }
    }
  ]
}

CloudWatchでお手軽文字列監視

CloudWatchを使ってお気軽な監視通知として、ファイル内の文字列を拾ってCludWatchのカスタムメトリクスに登録して、SNSで通知する方法を書きます。

環境内に監視システムを入れるほどでもなく、リージョンの都合でCludWatchLogsが利用できないといった場合に使えるのかと思います。

ロジックは簡単で、ファイル内で任意の文字列を拾ってawscliのcloudwatchを使ってカスタムメトリクスに登録して、その値をトリガにSNSでメール通知するというものです。
インスタンスにはawscliが必須になります。
awscliの導入はこちらを参考に。

実行できればどこのディレクトリでも構いませんのでインスタンスに以下のシェルを置きます。
/var/log/messages内に“error”という文字列がある場合メールが届くような設定を例にします。
必要に応じて対象Logファイルやキーワードは変更して下さい。

vi /root/check_error.sh

#!/bin/bash

MESSAGE=$(cat /var/log/messages | grep error | wc -l)

INSTANCE_ID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`

aws cloudwatch put-metric-data --metric-name Message_Check --value $MESSAGE --namespace messages --dimensions InstanceId=$INSTANCE_ID

試しに文字列"error”を/var/log/message内に書きます。

echo error >> /var/log/messages

先ほどのシェルを実行します。(権限を適当に755とかにして下さい。)

./check_error.sh


CloudWatchでカスタムメトリクスとして登録されているかを確認します。
f:id:toatoshi:20140718153537j:plain

Cloudwatchの通知設定をします。
f:id:toatoshi:20140718153551j:plain

SNSで設定されたemailアドレスへ、メール通知されているかを確認します。
f:id:toatoshi:20140718153605j:plain

cronでシェルを回せばその間隔で監視することが可能になります。

お好みの間隔でcronに登録しておけばお手軽にログの文字列監視が可能となります。
但し、無償のCloudwatchでは監視間隔で問題があったり、監視する文字列が多かったりする場合には監視専用のソフトを導入するのがいいですね。
CloudWatch Logsが東京に来るのが待ち遠しいですねー。

【参考資料】
Amazon Web Services ブログ: 【AWS発表】 クラウド監視サービスAmazon CloudWatchでカスタムのメトリクスが使用可能に

cloudwatch — AWS CLI 1.3.23 documentation

EBSデータを丸ごとS3へ

ちょっと珍しいリクエストをもらったので備忘ログ。

EBSVolumeをイメージとしてS3へ持っていきたいとの要望があったんだが、そんな機能は
AWSにはない。

ちょっと面倒だったがEBSを丸ごとバックアップできればよいとの事だったのでddを使って
ファイル化してあげるようにアドバイス。

1. Linuxインスタンスを用意し、EBS Volime状態でアタッチする。

2.アタッチしたボリュームを以下のコマンドでddでファイルに落とす。
# dd if=/dev/xvdf of=vol-xxxxxxxx.bin

3.このファイルをaws-cliを使ってS3バケットへアプロードする。

★戻すのは場合はインプットとアウトプットを逆にすればVolumeで復元できる。
# dd if=vol-xxxxxxxx.bin of=/dev/xvdf

OracleRDSの接続障害

ちょっとハマったので記録を残す。

数週間前にOracleRDSでバックアップからリストアしたインスタンスに接続出来なくなる
事象が起きました。

sqlplus64 username/password@oratest1212restore1.sokw9qsyc77w.ap-northeeast-1.rds.amazonaws.com:1521/dbname

SQL*Plus: Release 11.2.0.2.0 Production on Thu May 20 22:12:40 2014
Copylighat (c) 1982, 2010, Olacle.  All rights reserved.

ERROR:
ORA-12154: TNS:could not resolve connect identifier specified

Enter user-name:
Enter password:
ERROR:
ORA-12162: TNS:net service name is incorrectly specified

ユーザ名・パスワードが要求され、設定値に基づき入力しても弾かれてしまい、どうにも接続できない状況に陥りました。

Webでエラーコード参照すると海外サイトにsqlnet.oraの設定で同じような事象になることが書いてありましたが、sqlnet.oraは設定しておらずどうしようかと思ったところ、、、


メールにてお知らせが、、、、

ホスト名(Endpoint)の制限値が63byteとなっているようで、それ以上になるとsqlplus側でホスト名をハンドルできない状態となりORA-12154が出力するようです。

Endopointの後半部分は定形になっているのでDB Identifierを17文字以下で設定する必要があるという事になります。
あとは素直にTNSNAMES.ORAの書式で書くかです。

興味本位でMySQLで50文字のDB Identifierで起動し接続したら問題なく接続できたので、sqlplusのみの問題だと思います。