初めまして、PHPエンジニアの伊藤です。
AWSで別VPC上にあるEC2インスタンス間の接続をする際に
auth認証等独自の認証を利用せず フロント側のように
Cognitoを経由して接続することで認証を簡略化できないかと思い
試してみたのでその紹介をしようと思います。
前提
・今回はサーバ間の接続のためフロント側については考えない(ログイン画面等)
・サーバ間はAPIを通してやりとりする
・事前準備としてログイン用のユーザープールとログインユーザーの登録は済ませておく
だいぶ雑ですが簡略化するとこんなイメージ
では早速実装していきたいと思います。
PHP側
まずはadminInitiateAuthのAPIを利用して ログインしてアクセストークンを取得します。
protected function access_token() { $client = new CognitoIdentityProviderClient([ 'profile' => '***adminInitiateAuthの実行権限をもったロールのprofile***', 'region' => 'ap-northeast-1', 'version' => '2016-04-18', ]); $result = $client->adminInitiateAuth([ 'AuthFlow' => 'ADMIN_NO_SRP_AUTH', 'ExplicitAuthFlow ' => 'ADMIN_USER_PASSWORD_AUTH', 'AuthParameters' => [ 'USERNAME' => '***CognitoのログインユーザーID***', 'PASSWORD' => '***Cognitoのログインパスワード***' ], 'ClientId' => '***CognitoのClientID***', 'UserPoolId' => '***対象のユーザープールのID***' ]); $access_token = array('X-Authorization:'.$result['AuthenticationResult']['AccessToken']); return $access_token; }
上の関数で取得したアクセストークンをヘッダーに付与して対象のインスタンスにアクセス。
public function post($uri, $params) { $curl = curl_init($uri); //CURL初期化 curl_setopt($curl, CURLOPT_POST, TRUE); //POSTを指定 curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($params)); //POSTを指定 curl_setopt($curl, CURLOPT_HTTPHEADER, self::access_token()); //Cognitoのアクセストークンを付与 curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); //execの実行結果に取得結果を入れる $raw_result = curl_exec($curl); curl_close($curl); //結果に関わらず明示的にセッションを閉じておく if ($raw_result === false) { \log::debug(''); return false; } $result_array = json_decode($raw_result, true); return $result_array; }
これで接続可能になったと思います。
ソース全体だとこんな感じです。
<?php namespace App\Services; use Aws\CognitoIdentityProvider\CognitoIdentityProviderClient; /** * Cognitoでのサーバ間接続 * */ class Api { public function post($uri, $params) { $curl = curl_init($uri); //CURL初期化 curl_setopt($curl, CURLOPT_POST, TRUE); //POSTを指定 curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($params)); //POSTを指定 curl_setopt($curl, CURLOPT_HTTPHEADER, self::access_token()); //Cognitoのアクセストークンを付与 curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); //execの実行結果に取得結果を入れる $raw_result = curl_exec($curl); curl_close($curl); //結果に関わらず明示的にセッションを閉じておく if ($raw_result === false) { \log::debug(''); return false; } $result_array = json_decode($raw_result, true); return $result_array; } protected function access_token() { $client = new CognitoIdentityProviderClient([ 'profile' => '***adminInitiateAuthの実行権限をもったロールのprofile***', 'region' => 'ap-northeast-1', 'version' => '2016-04-18', ]); $result = $client->adminInitiateAuth([ 'AuthFlow' => 'ADMIN_NO_SRP_AUTH', 'ExplicitAuthFlow ' => 'ADMIN_USER_PASSWORD_AUTH', 'AuthParameters' => [ 'USERNAME' => '***CognitoのログインユーザーID***', 'PASSWORD' => '***Cognitoのログインパスワード***' ], 'ClientId' => '***CognitoのClientID***', 'UserPoolId' => '***対象のユーザープールのID***' ]); $access_token = array('X-Authorization:'.$result['AuthenticationResult']['AccessToken']); return $access_token; } }
サービスクラスとして実装してやって
Api::post('接続先APIエンドポイント','POSTで渡すパラメータ');
↑みたいに相手方のAPIを呼び出す度にアクセストークンを取得してくるイメージです。
結論
結論として、サーバ間認証もCognitoで実現できました。
ただし今回はあくまでお試し実装となります。
本番サービス等に導入する際は、adminInitiateAuthのロールを渡し
管理者権限でCognitoにログインすることになるので、
各自セキュリティ要件を満たせるかなど
色々と検討すべきハードルは多そうです。