AWS SDK for PHPでCloudFrontディストリビューションを作成する

PHPを使って、CloudFrontディストリビューションを作成してみます。
オリジンに設定するS3バケットも一気通貫で作成します。
マネジメントコンソールでやってみるとわかりますが、CloudFrontディストリビューションには鬼のように設定項目があります。


必然的にSDKのCreateDistributionメソッドのパラメータもえらいことになってます。
気合いで一つ一つ何の項目なのか調べながら設定しましょう。

事前準備

コードを実行する前にSDKを実行するためのIAMユーザーとCloudFrontのOrigin Access Identityを準備する必要があります。

IAMにはS3とCloudFrontの権限を付与(Lambda@Edgeを利用する場合はLambdaの権限も必要です)します。
SDKで使うためのクレデンシャルを発行しておきます。

Origin Access Identityはコンソールから取得できます。
IDをプログラムに埋め込む必要があるので控えておきましょう。

実装

実装コードがこちらです。
S3バケットを作って、HTMLファイルをアップロード。
バケットポリシーを付与して、作ったS3をオリジンにCloudFrontディストリビューションを作っています。
<?php
require 'vendor/autoload.php';

use Aws\S3\S3Client;
use Aws\CloudFront\CloudFrontClient;
use Aws\Exception\AwsException;

// 設定値
$credentials = [
    'key'       => '******************',
    'secret'    => '**************************************',
];
$originAccessIdentityId = 'E1OP42N2TFDBIW';

$s3client = S3Client::factory([
    'credentials' => $credentials,
    'region' => 'ap-northeast-1',
    'version' => 'latest',
]);

// S3バケット作成
echo '*** create bucket ***' . PHP_EOL;
$bucketName = 'cloudfront-test-' . date('ymdhis');
try{
    $result = $s3client->createBucket([
        'ACL' => 'private',
        'Bucket' => $bucketName,
    ]);
    print_r($result);
}catch (AwsException $e) {
    throw $e;
}
echo '--------------------------' . PHP_EOL;

// S3にファイルアップロード
echo '*** put object ***' . PHP_EOL;
$fileName = 'index.html';
file_put_contents($fileName, '<html><body><h1>It works!</h1></body></html>');
try{
    $result = $s3client->putObject([
        'Bucket'        => $bucketName,
        'Key'           => $fileName,
        'SourceFile'    => $fileName,
        'ContentType'   => mime_content_type($fileName),
    ]);
}catch (AwsException $e) {
    throw $e;
}
echo '--------------------------' . PHP_EOL;

// CloudFrontから参照するためのバケットポリシー付与
echo '*** put bucket policy ***' . PHP_EOL;
$policy = <<<EOF
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity {$originAccessIdentityId}"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::{$bucketName}/*"
        }
    ]
}
EOF;

try{
    $result = $s3client->putBucketPolicy([
        'Bucket' => $bucketName,
        'Policy' => $policy,
    ]);
}catch (AwsException $e) {
    throw $e;
}
echo '--------------------------' . PHP_EOL;

$cloudFrontClient = CloudFrontClient::factory([
    'credentials' => $credentials,
    'region' => 'us-east-1',
    'version' => 'latest',
]);

// ディストリビューションの作成
echo '*** create distribution ***' . PHP_EOL;
$originAccessIdentity = 'origin-access-identity/cloudfront/' . $originAccessIdentityId;
try{
    $result = $cloudFrontClient->createDistribution([
        'DistributionConfig' => [
            'CacheBehaviors' => ['Quantity' => 0],
            'CallerReference' => time(),
            'Comment' => 'コメント',
            'CustomErrorResponses' => [
                'Items' => [
                    [
                        'ErrorCachingMinTTL' => 0,
                        'ErrorCode' => 404,
                        'ResponseCode' => '404',
                        'ResponsePagePath' => '/404.html',
                    ],
                ],
                'Quantity' => 1,
            ],
            'DefaultCacheBehavior' => [
                'AllowedMethods' => [
                    'CachedMethods' => [
                        'Items' => ['HEAD', 'GET'],
                        'Quantity' => 2,
                    ],
                    'Items' => ['GET', 'HEAD'],
                    'Quantity' => 2,
                ],
                'Compress' => true,
                'DefaultTTL' => 10,
                'FieldLevelEncryptionId' => '',
                'ForwardedValues' => [
                    'Cookies' => [
                        'Forward' => 'none',
                    ],
                    'Headers' => ['Quantity' => 0],
                    'QueryString' => false,
                    'QueryStringCacheKeys' => ['Quantity' => 0],
                ],
                'LambdaFunctionAssociations' => ['Quantity' => 0],
                'MaxTTL' => 10,
                'MinTTL' => 10,
                'SmoothStreaming' => false,
                'TargetOriginId' => $bucketName,
                'TrustedSigners' => [
                    'Enabled' => false,
                    'Quantity' => 0,
                ],
                'ViewerProtocolPolicy' => 'redirect-to-https',
            ],
            'DefaultRootObject' => 'index.html',
            'Enabled' => true,
            'Origins' => [
                'Items' => [
                    [
                        'DomainName' => "{$bucketName}.s3.amazonaws.com",
                        'Id' => $bucketName,
                        'OriginPath' => '',
                        'CustomHeaders' => ['Quantity' => 0],
                        'S3OriginConfig' => [
                            'OriginAccessIdentity' => $originAccessIdentity,
                        ],
                    ],
                ],
                'Quantity' => 1,
            ],
        ],
    ]);
    print_r($result);
}catch (AwsException $e) {
    throw $e;
}

コマンドラインで実行します。
>php CreateDistribution.php

*** create bucket ***
Aws\Result Object
(
    [data:Aws\Result:private] => Array
        (
            [Location] => http://cloudfront-test-200228122642.s3.amazonaws.com/
            [@metadata] => Array
                (
                    [statusCode] => 200
                    [effectiveUri] => https://cloudfront-test-200228122642.s3.ap-northeast-1.amazonaws.com/
                    [headers] => Array
                        (
                            [x-amz-id-2] => LTuI4gpvApnrJ3kzOq1+D/BddvHkKD0Nm6f8/Mm8iIkMmziDH6YqVmWgrCp5O+d2nZ2SwI3BNAI=
                            [x-amz-request-id] => 50C9DFCA21707220
                            [date] => Thu, 27 Feb 2020 23:26:44 GMT
                            [location] => http://cloudfront-test-200228122642.s3.amazonaws.com/
                            [content-length] => 0
                            [server] => AmazonS3
                        )

                    [transferStats] => Array
                        (
                            [http] => Array
                                (
                                    [0] => Array
                                        (
                                        )

                                )

                        )

                )

        )

    [monitoringEvents:Aws\Result:private] => Array
        (
        )

)
--------------------------
*** put object ***
--------------------------
*** put bucket policy ***
--------------------------
*** create distribution ***
Aws\Result Object
(
    [data:Aws\Result:private] => Array
        (
            [Distribution] => Array
                (
                    [Id] => E3AH2RLPRS88PN
                    [ARN] => arn:aws:cloudfront::XXXXXXXXXXX:distribution/E3AH2RLPRS88PN
                    [Status] => InProgress
                    [LastModifiedTime] => Aws\Api\DateTimeResult Object
                        (
                            [date] => 2020-02-27 23:26:46.009000
                            [timezone_type] => 2
                            [timezone] => Z
                        )

                    [InProgressInvalidationBatches] => 0
                    [DomainName] => d36qio875q8p4s.cloudfront.net
                    [ActiveTrustedSigners] => Array
                        (
                            [Enabled] => 
                            [Quantity] => 0
                        )

                    [DistributionConfig] => Array
                        (
                            [CallerReference] => 1582846004
                            [Aliases] => Array
                                (
                                    [Quantity] => 0
                                )

                            [DefaultRootObject] => index.html
                            [Origins] => Array
                                (
                                    [Quantity] => 1
                                    [Items] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [Id] => cloudfront-test-200228122642
                                                    [DomainName] => cloudfront-test-200228122642.s3.amazonaws.com
                                                    [OriginPath] => 
                                                    [CustomHeaders] => Array
                                                        (
                                                            [Quantity] => 0
                                                        )

                                                    [S3OriginConfig] => Array
                                                        (
                                                            [OriginAccessIdentity] => origin-access-identity/cloudfront/E1OP42N2TFDBIW
                                                        )

                                                )

                                        )

                                )

                            [OriginGroups] => Array
                                (
                                    [Quantity] => 0
                                )

                            [DefaultCacheBehavior] => Array
                                (
                                    [TargetOriginId] => cloudfront-test-200228122642
                                    [ForwardedValues] => Array
                                        (
                                            [QueryString] => 
                                            [Cookies] => Array
                                                (
                                                    [Forward] => none
                                                )

                                            [Headers] => Array
                                                (
                                                    [Quantity] => 0
                                                )

                                            [QueryStringCacheKeys] => Array
                                                (
                                                    [Quantity] => 0
                                                )

                                        )

                                    [TrustedSigners] => Array
                                        (
                                            [Enabled] => 
                                            [Quantity] => 0
                                        )

                                    [ViewerProtocolPolicy] => redirect-to-https
                                    [MinTTL] => 10
                                    [AllowedMethods] => Array
                                        (
                                            [Quantity] => 2
                                            [Items] => Array
                                                (
                                                    [0] => HEAD
                                                    [1] => GET
                                                )

                                            [CachedMethods] => Array
                                                (
                                                    [Quantity] => 2
                                                    [Items] => Array
                                                        (
                                                            [0] => HEAD
                                                            [1] => GET
                                                        )

                                                )

                                        )

                                    [SmoothStreaming] => 
                                    [DefaultTTL] => 10
                                    [MaxTTL] => 10
                                    [Compress] => 1
                                    [LambdaFunctionAssociations] => Array
                                        (
                                            [Quantity] => 0
                                        )

                                    [FieldLevelEncryptionId] => 
                                )

                            [CacheBehaviors] => Array
                                (
                                    [Quantity] => 0
                                )

                            [CustomErrorResponses] => Array
                                (
                                    [Quantity] => 1
                                    [Items] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [ErrorCode] => 404
                                                    [ResponsePagePath] => /404.html
                                                    [ResponseCode] => 404
                                                    [ErrorCachingMinTTL] => 0
                                                )

                                        )

                                )

                            [Comment] => コメント
                            [Logging] => Array
                                (
                                    [Enabled] => 
                                    [IncludeCookies] => 
                                    [Bucket] => 
                                    [Prefix] => 
                                )

                            [PriceClass] => PriceClass_All
                            [Enabled] => 1
                            [ViewerCertificate] => Array
                                (
                                    [CloudFrontDefaultCertificate] => 1
                                    [MinimumProtocolVersion] => TLSv1
                                    [CertificateSource] => cloudfront
                                )

                            [Restrictions] => Array
                                (
                                    [GeoRestriction] => Array
                                        (
                                            [RestrictionType] => none
                                            [Quantity] => 0
                                        )

                                )

                            [WebACLId] => 
                            [HttpVersion] => http2
                            [IsIPV6Enabled] => 1
                        )

                )

            [Location] => https://cloudfront.amazonaws.com/2019-03-26/distribution/E3AH2RLPRS88PN
            [ETag] => EYM2CTGO51RJQ
            [@metadata] => Array
                (
                    [statusCode] => 201
                    [effectiveUri] => https://cloudfront.amazonaws.com/2019-03-26/distribution
                    [headers] => Array
                        (
                            [x-amzn-requestid] => 0826d3a5-a3e5-4082-9879-2a9274667829
                            [etag] => EYM2CTGO51RJQ
                            [location] => https://cloudfront.amazonaws.com/2019-03-26/distribution/E3AH2RLPRS88PN
                            [content-type] => text/xml
                            [content-length] => 3003
                            [vary] => Accept-Encoding
                            [date] => Thu, 27 Feb 2020 23:26:46 GMT
                        )

                    [transferStats] => Array
                        (
                            [http] => Array
                                (
                                    [0] => Array
                                        (
                                        )

                                )

                        )

                )

        )

    [monitoringEvents:Aws\Result:private] => Array
        (
        )

)
マネジメントコンソールで確認するとディストリビューションが作成されているのがわかります。
ビヘイビアやエラーページも設定されます。
ディストリビューションを作成後、一時間ほど待つと、ブラウザからアクセスできるようになります。


後日談

オリジンドメイン名を変えるとディストリビューションのデプロイ完了後すぐアクセスできます。

                        'DomainName' => "{$bucketName}.s3-ap-northeast-1.amazonaws.com",