AWSでWordPressサイトを構築 第4回〜CloudFront用セキュリティグループ設定〜

こんにちは。かっぺいです。
AWSでWordPressサイト構築、第4回。CloudFront用セキュリティグループ設定です。

第1回で、AWS環境を構築時に、EC2をパブリック領域に置いておきながら、クラウドフロントとの通信を限定すると記載しました。
今回は、実際にそのセキュリティグループ設定を行うスクリプトの構築方法を紹介します。

AWS SDK

今時ですと、Lambdaを使うのが普通かと思います。
今回はお手軽に実施したいので、Webサーバが常時起動するので、Webサーバから実行する環境にします。
さらに、Lambdaでは利用できないPHPでCLI制御する方法という意味も込めて紹介します。

PHPからAWSのAPIをコールするためには、AWS SDKが必要になります。
PHPのインストール手順ページから、ZIPダウンロードを選びます。

ダウンロードしたZIPは、これから作成するPHPのソースと同じフォルダに展開します。

IAMロール

EC2インスタンスから、EC2APIをコールするためのアクセス権限を付与したIAMロールをアタッチしておく必要があります。
第1回の時に、SSMでリモートログインするために作成したIAMロールに、AmazonEC2FullAccessを追加アタッチします。

php-xml

AWS SDKを利用するためには、php-xmlパッケージが追加で必要になります。
インストールしておきましょう。

# yum install php-xml

セキュリティグループの作成

EC2にアタッチするセキュリティグループを3個作成しておきます。
3個作る理由は、現時点でAWSが用意しているCloudFrontのエッジIPアドレス範囲が131個存在します。
しかし、セキュリティーグループにアタッチ可能なインバウンドルールの最大数は60に制限されています。

制限解除を要求しても良いのですが、一つのEC2インスタンスには5個のセキュリティグループをアタッチできますので、素直に3個作成して分割した方が手間もかからず、めんどくさい制限解除の手続きをしなくて済みます。

AWSサービスのIPレンジ情報

AWSでは、現在提供しているサービス毎の、IPアドレス範囲を公開しています。
https://ip-ranges.amazonaws.com/ip-ranges.json

今回使いたいのは、CloudFrontに関する情報ですので、Prefix配列内のサービスがCLODFRONTに関する、ip_prefixです。

セキュリティグループのインバウンド情報追加

EC2のAPI、authorizeSecurityGroupIngressがセキュリティグループのインバウンドに追加するAPIです。
こんな感じでPHPを作成します。

<?php
        require './aws/aws-autoloader.php';

        use Aws\Ec2\Ec2Client;
        use Aws\Exception\AwsException;

        $client = new Aws\Ec2\Ec2Client([
                'version' => 'latest',
                'region' => 'ap-northeast-1'
        ]);
        $sg = array("sg-ひとつ目のsgid","sg-ふたつ目のsgid","sg-三つ目のsgid") ;
        $sg_cnt = array(0,0,0) ;
        $si = -1 ;

        $ip_range = json_decode(file_get_contents("https://ip-ranges.amazonaws.com/ip-ranges.json"),true) ;

        foreach($ip_range['prefixes'] as $p){
                if($p['service'] === "CLOUDFRONT"){
                        if($p['ip_prefix'] != null){
                                print "IP: " . $p['ip_prefix'] . "\n" ;
                                if($sg_cnt[0] < 60){
                                        $si = 0 ;
                                }else if($sg_cnt[1] < 60){
                                        $si = 1 ;
                                }else if($sg_cnt[2] < 60){
                                        $si = 2 ;
                                }else{
                                        print "sg rules over\n" ;
                                        exit ;
                                }
                                $client->authorizeSecurityGroupIngress([
                                        'GroupId' => $sg[$si],
                                        'ToPort' => 80,
                                        'FromPort' => 80,
                                        'IpProtocol' => 'tcp',
                                        'CidrIp' => $p['ip_prefix'],
                                        ]) ;
                                $sg_cnt[$si]++ ;
                        }
                }
        }
?>

とりあえず動けば良いというレベルで作ったので、ちょっと素人っぽい内容になってしまっています。

  • JSONで取得した、CLOUDFRONTに関連するIPレンジを
  • それぞれ60個以内になるようなセキュリティグループIDを選んで
  • そのセキュリティグループにインバウンド情報を追加する

というようなことを実行しています。
ちなみに、インバウンドを削除することはしていないので、インバウンド情報があると60個超えるとエラーになります。

セキュリティグループのインバウンド情報を削除する

EC2のAPI、revoke-security-groupsがセキュリティグループのインバウンド情報の削除するAPIになります。
こんな感じでPHPを作成します。

<?php
        require './aws/aws-autoloader.php';

        use Aws\Ec2\Ec2Client;
        use Aws\Exception\AwsException;

        $client = new Aws\Ec2\Ec2Client([
                'version' => 'latest',
                'region' => 'ap-northeast-1'
        ]);
        $sg = array("sg-一つ目のsgid","sg-二つ目のsgid","sg-三つ目のsgid") ;

        foreach($sg as $s){
                $rules = $client->describeSecurityGroups([
                                'GroupIds' => [$s,],
                ]) ;
                if(count($rules['SecurityGroups'][0]['IpPermissions']) != 0){
                        foreach($rules['SecurityGroups'][0]['IpPermissions'][0]['IpRanges'] as $r){
                                print "IP: " . $r['CidrIp'] . "\n" ;
                        }
                        $param = [
                                'GroupId' => $s,
                                'IpPermissions' => [
                                        [
                                                'FromPort' => 80,
                                                'ToPort' => 80,
                                                'IpProtocol' => 'tcp',
                                                'IpRanges' => $rules['SecurityGroups'][0]['IpPermissions'][0]['IpRanges'],
                                        ],
                                ],
                        ] ;
                        $client->revokeSecurityGroupIngress($param) ;
                }
        }
?>

セキュリティグループに登録されているインバウンド情報を全て削除するスクリプトです。

レンジ情報の変更判断

サービス変更やリージョン追加などで時々、変更されているようです。
JSONファイルにある、syncTokenの数値が前回取得から変更となっていたら、どこかが変更となっているので再取り込みを実施するようにしましょう。