Cognitoでサーバ間接続してみる

初めまして、PHPエンジニアの伊藤です。

AWSで別VPC上にあるEC2インスタンス間の接続をする際に
auth認証等独自の認証を利用せず フロント側のように
Cognitoを経由して接続することで認証を簡略化できないかと思い
試してみたのでその紹介をしようと思います。

前提

・今回はサーバ間の接続のためフロント側については考えない(ログイン画面等)
・サーバ間はAPIを通してやりとりする
・事前準備としてログイン用のユーザープールとログインユーザーの登録は済ませておく

だいぶ雑ですが簡略化するとこんなイメージ

f:id:teco_ito:20200614113257p:plain
イメージ図

では早速実装していきたいと思います。

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にログインすることになるので、
各自セキュリティ要件を満たせるかなど
色々と検討すべきハードルは多そうです。

参考: https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-server-side-authentication-flow

https://docs.aws.amazon.com/ja_jp/aws-sdk-php/v3/api/api-cognito-idp-2016-04-18.html#admininitiateauth

tecotec.co.jp