AWSのAPIを叩く(PHP 5)

On 2011年12月10日, in AWS, PHP, by タカ

PHPからAWS(EC2)のAPIを叩いてみたので書いてみる。

AWSの公式SDKがあるけど勉強がてらやってみた。

仕様は、

http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/

に書いてある。



準備

まずは、以下の二つを発行する。(AWSの管理コンソールの右上の「Security Credentials」から)

  1. アクセスキーID
  2. シークレットアクセスキー

すでに発行しているならばそれでもOK

Endpointを決める

リージョンによって叩く場所が異なる。

http://docs.amazonwebservices.com/general/latest/gr/index.html?rande.html#ec2_region

東京リージョンの場合はec2.ap-northeast-1.amazonaws.com

叩くAPI(Action)を決める

次に叩くAPIを決める。
インスタンスを起動したい!とかタグを打ちたい!とか。

http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?OperationList-query.html

今回は、インスタンス一覧取得(DescribeInstances)を選択したみる。

Action固有のパラメータを決める

Actionによって色んなパラメータがあるので、それぞれの仕様をみて決める。

DescribeInstancesはパラメータなしでも叩ける。

今回は、マイクロインスタンスで絞ってみる。

Key Value
Filter.1.Name instance-type
Filter.1.Value.1 t1.micro

必須パラメータを追加

EC2のAPIの場合、幾つか必須のパラメータがあるのでそれを追加。

http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?Query-Common-Parameters.html

Key Value
Action アクション名(今回は、DescribeInstances)
Version APIのバージョン(今回は、2011-11-01)
AWSAccessKeyId アクセスキーID
Timestamp YYYY-MM-DDThh:mm:ssZ(date(‘c’)で取得できる)
Signature 後述する方法で生成
SignatureMethod HmacSHA256 or HMacSHA1
SignatureVersion 2

これに、Action固有のパラメータを足したものが最終的に送るパラメータ。

Signatureの生成

オープンソーシャルなAPIも似たような方法で署名してた気がする。

手順は、

  1. 各Keyを元にソート(ksort)
  2. Key,ValueをURLEncode(RFC 3986)して&で連結
  3. 署名に使う文字列を生成(HTTPメソッド名+EndPoint+path+連結したパラメータ)
  4. 上記文字列とシークレットアクセスキーを使ってハッシュ生成(HMAC-SHA256 or HMAC-SHA1)
  5. base64エンコード

コードにすると以下のような感じ。
(HTTPメソッドとかベタ書きだけど…)

<?php
class Signer
{
    function sign($params, $secretAccessKey)
    {
        $params = $this->sortByKey($params);
        $string = $this->buildCanonicalString($params);
        $stringToSign = $this->buildStringToSign($string);
        $signature = base64_encode($this->hash($stringToSign, $secretAccessKey));
        return $signature;
    }

    private function sortByKey($params)
    {
        ksort($params);
        return $params;
    }

    private function buildCanonicalString($params)
    {
        $strings = array();
        foreach ($params as $key => $value) {
            $strings[] = $this->urlencode($key) . '=' . $this->urlencode($value);
        }
        return implode('&', $strings);
    }

    private function buildStringToSign($string)
    {
        $stringToSign = "GET\n"
                      . "ec2.ap-northeast-1.amazonaws.com\n"
                      . "/\n"
                      . $string;
        return $stringToSign;
    }

    private function hash($stringToSign, $secretAccessKey)
    {
        return hash_hmac('sha256', $stringToSign, $secretAccessKey, true);
    }

    // PHP 5.2.X系はチルダもエンコードするので元に戻す
    private function urlencode($value)
    {
        return str_replace('%7E', '~', rawurlencode($value));
    }
}

※PHP5.2系の環境はなかったので、PHP5.3でしか動作確認していない。

HTTPリクエスト送信

この時点で送信するパラメータはすべて揃ったので、file_get_contentsなりCurlなりお好きなようにどうぞ。

結果はXMLとして帰ってくるので、これもまたお好きなように。

まとめ

Signatureの生成がちょっと面倒だけど、そこ以外は特にハマるところはないと思う。

Signature生成/Httpリクエスト送信/EndPoint/ハッシュアルゴリズム

辺りを分離したクラスを作れば立派な簡易クライアントの出来上がり!

それは、また時間のある時にでも…。

Tagged with: