「AWS 上で静的な Web サイトを公開しよう！」をAWS CLIでやってみる

https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-StaticWebsiteHosting-2022-reg-event.html?trk=aws_introduction_page

上記、「AWS 上で静的な Web サイトを公開しよう！」 をAWS CLIでやってみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3297641/3efa9f1d-95e0-1eee-f5dd-c32bca7a3806.png)
ハンズオンから引用
# 1. S3 の静的ホスティング機能を使ってみる
## S3バケット作成
```bash:コマンド
# S3バケット名
S3_BUCKET_NAME="handson.example.com" \
&& echo ${S3_BUCKET_NAME}

# S3バケット作成
aws s3api create-bucket \
    --bucket ${S3_BUCKET_NAME} \
    --create-bucket-configuration LocationConstraint=ap-northeast-1

# パブリックアクセスをすべてブロック：オフ
aws s3api put-public-access-block \
    --bucket ${S3_BUCKET_NAME} \
    --public-access-block-configuration 'BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false'

# 静的ウェブサイトホスティング
aws s3 website s3://${S3_BUCKET_NAME}/ \
    --index-document index.html
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # S3バケット名
[cloudshell-user@ip-10-130-61-60 ~]$ S3_BUCKET_NAME="handson.example.com" \
> && echo ${S3_BUCKET_NAME}
handson.example.com
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # S3バケット作成
[cloudshell-user@ip-10-130-61-60 ~]$ aws s3api create-bucket \
>     --bucket ${S3_BUCKET_NAME} \
>     --create-bucket-configuration LocationConstraint=ap-northeast-1
{
    "Location": "http://handson.example.com.s3.amazonaws.com/"
}
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # パブリックアクセスをすべてブロック：オフ
[cloudshell-user@ip-10-130-61-60 ~]$ aws s3api put-public-access-block \
>     --bucket ${S3_BUCKET_NAME} \
>     --public-access-block-configuration 'BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false'
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # 静的ウェブサイトホスティング
[cloudshell-user@ip-10-130-61-60 ~]$ aws s3 website s3://${S3_BUCKET_NAME}/ \
>     --index-document index.html
```
# バケットポリシー適用
```bash:コマンド
# バケットポリシー(JSON)
BACKET_POLICY=$(cat << EOF
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "PublicReadGetObject",
          "Effect": "Allow",
          "Principal": "*",
          "Action": [
              "s3:GetObject"
          ],
          "Resource": [
              "arn:aws:s3:::${S3_BUCKET_NAME}/*"
          ]
      }
  ]
}
EOF
) \
&& echo ${BACKET_POLICY}

# JSONフォーマットの確認
echo ${BACKET_POLICY} | python -m json.tool

# バケットポリシー
aws s3api put-bucket-policy \
    --bucket ${S3_BUCKET_NAME} \
    --policy "${BACKET_POLICY}"
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # バケットポリシー(JSON)
[cloudshell-user@ip-10-130-61-60 ~]$ BACKET_POLICY=$(cat << EOF
> {
>   "Version": "2012-10-17",
>   "Statement": [
>       {
>           "Sid": "PublicReadGetObject",
>           "Effect": "Allow",
>           "Principal": "*",
>           "Action": [
>               "s3:GetObject"
>           ],
>           "Resource": [
>               "arn:aws:s3:::${S3_BUCKET_NAME}/*"
>           ]
>       }
>   ]
> }
> EOF
> ) \
> && echo ${BACKET_POLICY}
{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": [ "s3:GetObject" ], "Resource": [ "arn:aws:s3:::handson.example.com/*" ] } ] }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${BACKET_POLICY} | python -m json.tool
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::handson.example.com/*"
            ]
        }
    ]
}
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # バケットポリシー
[cloudshell-user@ip-10-130-61-60 ~]$ aws s3api put-bucket-policy \
>     --bucket ${S3_BUCKET_NAME} \
>     --policy "${BACKET_POLICY}"
```
## index.htmlのアップロード
```bash:コマンド
aws s3 cp index.html s3://${S3_BUCKET_NAME}/
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ aws s3 cp index.html s3://${S3_BUCKET_NAME}/
upload: ./index.html to s3://handson.example.com/index.html 
```
## アクセス確認
```bash:コマンド
curl http://handson.example.com.s3-website-ap-northeast-1.amazonaws.com/
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ curl http://handson.example.com.s3-website-ap-northeast-1.amazonaws.com/
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての S3 静的 Web サイトホスティング</title>
</head>
<body>
  <div>
    <div class="msg">
      Hello, AWS World!!
    </div>
  </div>
</body>
```
# 2. Cloud9 環境を立ち上げて静的コンテンツを開発する + AWS CLI で S3 にファイルアップロードする
## Cloud9環境作成
```bash:コマンド
# Cloud9環境名
CLOUD9_ENVIRONMENT_NAME="hands-on" \
&& echo ${CLOUD9_ENVIRONMENT_NAME}

# Cloud9環境作成
CLOUD9_ENVIRONMENT_ID=$(
    aws cloud9 create-environment-ec2 \
        --name ${CLOUD9_ENVIRONMENT_NAME} \
        --instance-type t2.micro \
        --image-id resolve:ssm:/aws/service/cloud9/amis/amazonlinux-2-x86_64 \
        --connection-type CONNECT_SSM \
        --automatic-stop-time-minutes 30 \
        --query environmentId \
        --output text
) \
&& echo ${CLOUD9_ENVIRONMENT_ID}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # Cloud9環境名
[cloudshell-user@ip-10-130-61-60 ~]$ CLOUD9_ENVIRONMENT_NAME="hands-on" \
> && echo ${CLOUD9_ENVIRONMENT_NAME}
hands-on
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # Cloud9環境作成
[cloudshell-user@ip-10-130-61-60 ~]$ CLOUD9_ENVIRONMENT_ID=$(
>     aws cloud9 create-environment-ec2 \
>         --name ${CLOUD9_ENVIRONMENT_NAME} \
>         --instance-type t2.micro \
>         --image-id resolve:ssm:/aws/service/cloud9/amis/amazonlinux-2-x86_64 \
>         --connection-type CONNECT_SSM \
>         --automatic-stop-time-minutes 30 \
>         --query environmentId \
>         --output text
> ) \
> && echo ${CLOUD9_ENVIRONMENT_ID}
1fab01bdfd684c26afbc4bf5e60af558
```
## 作業用ディレクトリ作成
```bash:コマンド
mkdir my-webpage
cd my-webpage/
```
```bash:出力
admin:~/environment $ mkdir my-webpage
admin:~/environment $ cd my-webpage/
```
## 静的コンテンツを開発
```bash:コマンド
cat << EOF > index.html
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての AWS</title>
</head>
<body>
  <div>
    <div class="msg">
      このページでは、AWS について学んだことを書いていきます。
    </div>
  </div>
</body>
</html>
EOF
cat index.html
```
```bash:出力
admin:~/environment/my-webpage $ cat << EOF > index.html
> <!DOCTYPE html>
> 
> <html lang="ja">
> <head>
>   <meta charset="utf-8">
>   <title>はじめての AWS</title>
> </head>
> <body>
>   <div>
>     <div class="msg">
>       このページでは、AWS について学んだことを書いていきます。
>     </div>
>   </div>
> </body>
> </html>
> EOF
admin:~/environment/my-webpage $ cat index.html
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての AWS</title>
</head>
<body>
  <div>
    <div class="msg">
      このページでは、AWS について学んだことを書いていきます。
    </div>
  </div>
</body>
</html>
```
## index.htmlのアップロード
```bash:コマンド
aws s3 cp index.html s3://handson.example.com
```
```bash:出力
admin:~/environment/my-webpage $ aws s3 cp index.html s3://handson.example.com
upload: ./index.html to s3://handson.example.com/index.html 
```
## アクセス確認
```bash:コマンド
curl http://handson.example.com.s3-website-ap-northeast-1.amazonaws.com/
```
```bash:出力
admin:~/environment/my-webpage $ curl http://handson.example.com.s3-website-ap-northeast-1.amazonaws.com/
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての AWS</title>
</head>
<body>
  <div>
    <div class="msg">
      このページでは、AWS について学んだことを書いていきます。
    </div>
  </div>
</body>
</html>
```
# 3. 続・静的コンテンツの開発 + AWS CLI で S3 に複数のファイルを一括アップロードする
## ディレクトリ作成
```bash:コマンド
mkdir img
mkdir css
touch css/styles.css
```
```bash:出力
admin:~/environment/my-webpage $ mkdir img
admin:~/environment/my-webpage $ mkdir css
admin:~/environment/my-webpage $ touch css/styles.css
```
:::note info
ハンズオンからダウンロードしたファイルをCloud9環境にアップロード
lambda.png : /home/ec2-user/environment/my-webpage/img
favicon.ico : /home/ec2-user/environment/my-webpage
:::
## index.html修正
```bash:コマンド
cat << EOF > index.html
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての AWS</title>
  <link rel="icon" href="favicon.ico">
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div>
  　<div class="icon">
      <img src="img/lambda.png">
    </div>
    <div class="msg">
      このページでは、AWS について学んだことを書いていきます。
    </div>
  </div>
</body>
</html>
EOF
cat index.html
```
```bash:出力
admin:~/environment/my-webpage $ cat << EOF > index.html
> <!DOCTYPE html>
> 
> <html lang="ja">
> <head>
>   <meta charset="utf-8">
>   <title>はじめての AWS</title>
>   <link rel="icon" href="favicon.ico">
>   <link rel="stylesheet" href="css/styles.css">
> </head>
> <body>
>   <div>
>   　<div class="icon">
>       <img src="img/lambda.png">
>     </div>
>     <div class="msg">
>       このページでは、AWS について学んだことを書いていきます。
>     </div>
>   </div>
> </body>
> </html>
> EOF
admin:~/environment/my-webpage $ cat index.html
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての AWS</title>
  <link rel="icon" href="favicon.ico">
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div>
  　<div class="icon">
      <img src="img/lambda.png">
    </div>
    <div class="msg">
      このページでは、AWS について学んだことを書いていきます。
    </div>
  </div>
</body>
</html>
```
## styles.css作成
```bash:コマンド
cat << EOF > css/styles.css
body {
  width: 300px;
  margin-left: auto;
  margin-right: auto;
}

.icon img {
  padding-top: 16px;
  padding-bottom: 16px;
}
EOF
cat css/styles.css
```
```bash:出力
admin:~/environment/my-webpage $ cat << EOF > css/styles.css
> body {
>   width: 300px;
>   margin-left: auto;
>   margin-right: auto;
> }
> 
> .icon img {
>   padding-top: 16px;
>   padding-bottom: 16px;
> }
> EOF
admin:~/environment/my-webpage $ cat css/styles.css
body {
  width: 300px;
  margin-left: auto;
  margin-right: auto;
}

.icon img {
  padding-top: 16px;
  padding-bottom: 16px;
}
```
## ファイルのアップロード
```bash:コマンド
aws s3 cp . s3://handson.example.com --recursive
```
```bash:出力
admin:~/environment/my-webpage $ aws s3 cp . s3://handson.example.com --recursive
upload: css/styles.css to s3://handson.example.com/css/styles.css
upload: ./favicon.ico to s3://handson.example.com/favicon.ico
upload: img/lambda.png to s3://handson.example.com/img/lambda.png
upload: ./index.html to s3://handson.example.com/index.html
```
## アクセス確認
```bash:コマンド
curl http://handson.example.com.s3-website-ap-northeast-1.amazonaws.com/
```
```bash:出力
admin:~/environment/my-webpage $ curl http://handson.example.com.s3-website-ap-northeast-1.amazonaws.com/
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての AWS</title>
  <link rel="icon" href="favicon.ico">
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div>
  　<div class="icon">
      <img src="img/lambda.png">
    </div>
    <div class="msg">
      このページでは、AWS について学んだことを書いていきます。
    </div>
  </div>
</body>
</html>
```
# 4. CloudFront を使って、画像をキャッシュさせる
## CloudFront作成
```bash:コマンド
# 変数
ORIGIN_DOMAIN_NAME="${S3_BUCKET_NAME}.s3-website-ap-northeast-1.amazonaws.com" \
&& echo ${ORIGIN_DOMAIN_NAME}

# ディストリビューションを作成
aws cloudfront create-distribution \
    --origin-domain-name ${ORIGIN_DOMAIN_NAME}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # 変数
[cloudshell-user@ip-10-130-61-60 ~]$ ORIGIN_DOMAIN_NAME="${S3_BUCKET_NAME}.s3-website-ap-northeast-1.amazonaws.com" \
> && echo ${ORIGIN_DOMAIN_NAME}
handson.example.com.s3-website-ap-northeast-1.amazonaws.com
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # ディストリビューションを作成
[cloudshell-user@ip-10-130-61-60 ~]$ aws cloudfront create-distribution \
>     --origin-domain-name ${ORIGIN_DOMAIN_NAME}
{
    "Location": "https://cloudfront.amazonaws.com/2020-05-31/distribution/E4GYIQL4T0TP0",
    "ETag": "E95HZYNGU9MLI",
    "Distribution": {
        "Id": "E4GYIQL4T0TP0",
        "ARN": "arn:aws:cloudfront::999999999999:distribution/E4GYIQL4T0TP0",
        "Status": "InProgress",
        "LastModifiedTime": "2024-07-21T09:57:38.143000+00:00",
        "InProgressInvalidationBatches": 0,
        "DomainName": "d2xpr76fxshx5q.cloudfront.net",
        "ActiveTrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ActiveTrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "DistributionConfig": {
            "CallerReference": "cli-1721555857-121159",
            "Aliases": {
                "Quantity": 0
            },
            "DefaultRootObject": "",
            "Origins": {
                "Quantity": 1,
                "Items": [
                    {
                        "Id": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                        "DomainName": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "CustomOriginConfig": {
                            "HTTPPort": 80,
                            "HTTPSPort": 443,
                            "OriginProtocolPolicy": "http-only",
                            "OriginSslProtocols": {
                                "Quantity": 3,
                                "Items": [
                                    "TLSv1",
                                    "TLSv1.1",
                                    "TLSv1.2"
                                ]
                            },
                            "OriginReadTimeout": 30,
                            "OriginKeepaliveTimeout": 5
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": ""
                    }
                ]
            },
            "OriginGroups": {
                "Quantity": 0
            },
            "DefaultCacheBehavior": {
                "TargetOriginId": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                "TrustedSigners": {
                    "Enabled": false,
                    "Quantity": 0
                },
                "TrustedKeyGroups": {
                    "Enabled": false,
                    "Quantity": 0
                },
                "ViewerProtocolPolicy": "allow-all",
                "AllowedMethods": {
                    "Quantity": 2,
                    "Items": [
                        "HEAD",
                        "GET"
                    ],
                    "CachedMethods": {
                        "Quantity": 2,
                        "Items": [
                            "HEAD",
                            "GET"
                        ]
                    }
                },
                "SmoothStreaming": false,
                "Compress": false,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "ForwardedValues": {
                    "QueryString": false,
                    "Cookies": {
                        "Forward": "none"
                    },
                    "Headers": {
                        "Quantity": 0
                    },
                    "QueryStringCacheKeys": {
                        "Quantity": 0
                    }
                },
                "MinTTL": 0,
                "DefaultTTL": 86400,
                "MaxTTL": 31536000
            },
            "CacheBehaviors": {
                "Quantity": 0
            },
            "CustomErrorResponses": {
                "Quantity": 0
            },
            "Comment": "",
            "Logging": {
                "Enabled": false,
                "IncludeCookies": false,
                "Bucket": "",
                "Prefix": ""
            },
            "PriceClass": "PriceClass_All",
            "Enabled": true,
            "ViewerCertificate": {
                "CloudFrontDefaultCertificate": true,
                "SSLSupportMethod": "vip",
                "MinimumProtocolVersion": "TLSv1",
                "CertificateSource": "cloudfront"
            },
            "Restrictions": {
                "GeoRestriction": {
                    "RestrictionType": "none",
                    "Quantity": 0
                }
            },
            "WebACLId": "",
            "HttpVersion": "http2",
            "IsIPV6Enabled": true,
            "ContinuousDeploymentPolicyId": "",
            "Staging": false
        }
    }
}
```
## 変数取得
```bash:コマンド
# ディストリビューションIDを変数に保存
DISTRIBUTION_ID=$(
    aws cloudfront list-distributions \
        --query "DistributionList.Items[?Origins.Items[?DomainName=='${ORIGIN_DOMAIN_NAME}']].Id" \
        --output text
) \
&& echo ${DISTRIBUTION_ID}

# ディストリビューションドメイン名を変数に保存
DISTRIBUTION_DOMAINNAME=$(
    aws cloudfront list-distributions \
        --query "DistributionList.Items[?Origins.Items[?DomainName=='${ORIGIN_DOMAIN_NAME}']].DomainName" \
        --output text
) \
&& echo ${DISTRIBUTION_DOMAINNAME}

# ディストリビューションARNを変数に保存
DISTRIBUTION_ARN=$(
    aws cloudfront get-distribution \
        --id ${DISTRIBUTION_ID} \
        --query "Distribution.ARN" \
        --output text
) \
&& echo ${DISTRIBUTION_ARN}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # ディストリビューションIDを変数に保存
[cloudshell-user@ip-10-130-61-60 ~]$ DISTRIBUTION_ID=$(
>     aws cloudfront list-distributions \
>         --query "DistributionList.Items[?Origins.Items[?DomainName=='${ORIGIN_DOMAIN_NAME}']].Id" \
>         --output text
> ) \
> && echo ${DISTRIBUTION_ID}
E4GYIQL4T0TP0
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # ディストリビューションドメイン名を変数に保存
[cloudshell-user@ip-10-130-61-60 ~]$ DISTRIBUTION_DOMAINNAME=$(
>     aws cloudfront list-distributions \
>         --query "DistributionList.Items[?Origins.Items[?DomainName=='${ORIGIN_DOMAIN_NAME}']].DomainName" \
>         --output text
> ) \
> && echo ${DISTRIBUTION_DOMAINNAME}
d2xpr76fxshx5q.cloudfront.net
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # ディストリビューションARNを変数に保存
[cloudshell-user@ip-10-130-61-60 ~]$ DISTRIBUTION_ARN=$(
>     aws cloudfront get-distribution \
>         --id ${DISTRIBUTION_ID} \
>         --query "Distribution.ARN" \
>         --output text
> ) \
> && echo ${DISTRIBUTION_ARN}
arn:aws:cloudfront::999999999999:distribution/E4GYIQL4T0TP0
```
## アクセス確認
```bash:コマンド
curl http://d2xpr76fxshx5q.cloudfront.net/
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ curl http://d2xpr76fxshx5q.cloudfront.net/
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての AWS</title>
  <link rel="icon" href="favicon.ico">
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div>
  　<div class="icon">
      <img src="img/lambda.png">
    </div>
    <div class="msg">
      このページでは、AWS について学んだことを書いていきます。
    </div>
  </div>
</body>
</html>
```
# 5. [Option / Demo] Route 53 で独自ドメインを取得し、S3 に HTTP アクセスする
:::note warn
ハンズオン内ではAWSでドメインの取得を行っていたが、Googleドメイン(Squarespace)で取得していたテスト用ドメインがあったため、サブドメインを設定してそれで代用
:::
## ホストゾーン登録
:::note warn
AWSで取得したドメインではないため、手動でホストゾーンを登録
:::
```bash:コマンド
# ドメイン名
HOSTED_ZONE_NAME="handson.example.com" \
&& echo ${HOSTED_ZONE_NAME}

aws route53 create-hosted-zone \
    --name ${HOSTED_ZONE_NAME} \
    --caller-reference `date +"%Y-%m-%d-%H-%M"`

# ホストゾーンIDを取得
HOSTED_ZONE_ID=$(\
    aws route53 list-hosted-zones \
        --query "HostedZones[?Name=='${HOSTED_ZONE_NAME}.'].Id" \
        --output text
) \
&& echo ${HOSTED_ZONE_ID}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # ドメイン名
[cloudshell-user@ip-10-130-61-60 ~]$ HOSTED_ZONE_NAME="handson.example.com" \
> && echo ${HOSTED_ZONE_NAME}
handson.example.com
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ aws route53 create-hosted-zone \
>     --name ${HOSTED_ZONE_NAME} \
>     --caller-reference `date +"%Y-%m-%d-%H-%M"`
{
    "Location": "https://route53.amazonaws.com/2013-04-01/hostedzone/Z0649758FK3WFRRBZQNW",
    "HostedZone": {
        "Id": "/hostedzone/Z0649758FK3WFRRBZQNW",
        "Name": "handson.example.com.",
        "CallerReference": "2024-07-21-10-25",
        "Config": {
            "PrivateZone": false
        },
        "ResourceRecordSetCount": 2
    },
    "ChangeInfo": {
        "Id": "/change/C00350601ZVV4NNFDA7CG",
        "Status": "PENDING",
        "SubmittedAt": "2024-07-21T10:25:39.064000+00:00"
    },
    "DelegationSet": {
        "NameServers": [
            "ns-1260.awsdns-29.org",
            "ns-902.awsdns-48.net",
            "ns-1560.awsdns-03.co.uk",
            "ns-461.awsdns-57.com"
        ]
    }
}
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # ホストゾーンIDを取得
[cloudshell-user@ip-10-130-61-60 ~]$ HOSTED_ZONE_ID=$(\
>     aws route53 list-hosted-zones \
>         --query "HostedZones[?Name=='${HOSTED_ZONE_NAME}.'].Id" \
>         --output text
> ) \
> && echo ${HOSTED_ZONE_ID}
/hostedzone/Z0649758FK3WFRRBZQNW
```
:::note warn
表示されたNameSersをサブドメインのNSレコードとして登録する
:::
```bash:コマンド
# レコード登録用JSON
RECORD_JSON=$(cat << EOF
{
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "${HOSTED_ZONE_NAME}",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z2M4EHUR26P7ZW",
          "DNSName": "s3-website-ap-northeast-1.amazonaws.com.",
          "EvaluateTargetHealth": true
        }
      }
    }
  ]
}
EOF
) \
&& echo ${RECORD_JSON}

# JSONフォーマットの確認
echo ${RECORD_JSON} | python -m json.tool

# レコード作成
aws route53 change-resource-record-sets \
    --hosted-zone-id ${HOSTED_ZONE_ID} \
    --change-batch "${RECORD_JSON}"
```
:::note alert
"HostedZoneId": "Z2M4EHUR26P7ZW",  
// S3のウェブサイトホスティング用の固定Hosted Zone ID
 "DNSName": "s3-website-ap-northeast-1.amazonaws.com.", 
// S3バケットのリージョンに対応するエンドポイント
:::
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # レコード登録用JSON
[cloudshell-user@ip-10-130-61-60 ~]$ RECORD_JSON=$(cat << EOF
> {
>   "Changes": [
>     {
>       "Action": "UPSERT",
>       "ResourceRecordSet": {
>         "Name": "${HOSTED_ZONE_NAME}",
>         "Type": "A",
>         "AliasTarget": {
>           "HostedZoneId": "Z2M4EHUR26P7ZW",
>           "DNSName": "s3-website-ap-northeast-1.amazonaws.com.",
>           "EvaluateTargetHealth": true
>         }
>       }
>     }
>   ]
> }
> EOF
> ) \
> && echo ${RECORD_JSON}
{ "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "handson.example.com", "Type": "A", "AliasTarget": { "HostedZoneId": "Z2M4EHUR26P7ZW", "DNSName": "s3-website-ap-northeast-1.amazonaws.com.", "EvaluateTargetHealth": true } } } ] }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${RECORD_JSON} | python -m json.tool
{
    "Changes": [
        {
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": "handson.example.com",
                "Type": "A",
                "AliasTarget": {
                    "HostedZoneId": "Z2M4EHUR26P7ZW",
                    "DNSName": "s3-website-ap-northeast-1.amazonaws.com.",
                    "EvaluateTargetHealth": true
                }
            }
        }
    ]
}
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # レコード作成
[cloudshell-user@ip-10-130-61-60 ~]$ aws route53 change-resource-record-sets \
>     --hosted-zone-id ${HOSTED_ZONE_ID} \
>     --change-batch "${RECORD_JSON}"
{
    "ChangeInfo": {
        "Id": "/change/C0988662NXJC47I5XS7H",
        "Status": "PENDING",
        "SubmittedAt": "2024-07-21T10:29:15.797000+00:00"
    }
}
```
## アクセス確認
```bash:コマンド
curl http://handson.example.com/
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ curl http://handson.example.com/
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての AWS</title>
  <link rel="icon" href="favicon.ico">
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div>
  　<div class="icon">
      <img src="img/lambda.png">
    </div>
    <div class="msg">
      このページでは、AWS について学んだことを書いていきます。
    </div>
  </div>
</body>
</html>
```
# 6. [Option / Demo] ACM を使い、Route 53 - CloudFront - S3 で HTTPS アクセスする
:::note warn
証明書はus-east-1リージョン(バージニア北部)に作成する
:::
## 証明書の作成 (ACM)
### 証明書の作成
```bash:コマンド
# 証明書の作成
aws acm request-certificate \
    --domain-name ${HOSTED_ZONE_NAME} \
    --validation-method DNS \
    --region us-east-1

# 証明書のARN取得
CERTIFICATE_ARN=$(
    aws acm list-certificates \
        --region us-east-1 \
            --query "CertificateSummaryList[?DomainName=='${HOSTED_ZONE_NAME}'].CertificateArn" \
            --output text
) &&
echo ${CERTIFICATE_ARN}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # 証明書の作成
[cloudshell-user@ip-10-130-61-60 ~]$ aws acm request-certificate \
>     --domain-name ${HOSTED_ZONE_NAME} \
>     --validation-method DNS \
>     --region us-east-1
{
    "CertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56"
}
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # 証明書のARN取得
[cloudshell-user@ip-10-130-61-60 ~]$ CERTIFICATE_ARN=$(
>     aws acm list-certificates \
>         --region us-east-1 \
>             --query "CertificateSummaryList[?DomainName=='${HOSTED_ZONE_NAME}'].CertificateArn" \
>             --output text
> ) &&
> echo ${CERTIFICATE_ARN}
arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56
```
### 証明書の確認
```bash:コマンド
aws acm describe-certificate \
    --certificate-arn ${CERTIFICATE_ARN} \
    --region us-east-1
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ aws acm describe-certificate \
>     --certificate-arn ${CERTIFICATE_ARN} \
>     --region us-east-1
{
    "Certificate": {
        "CertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
        "DomainName": "handson.example.com",
        "SubjectAlternativeNames": [
            "handson.example.com"
        ],
        "DomainValidationOptions": [
            {
                "DomainName": "handson.example.com",
                "ValidationDomain": "handson.example.com",
                "ValidationStatus": "PENDING_VALIDATION",
                "ResourceRecord": {
                    "Name": "_e049795f32552612c6135c8d935dd7e5.handson.example.com.",
                    "Type": "CNAME",
                    "Value": "_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws."
                },
                "ValidationMethod": "DNS"
            }
        ],
        "Subject": "CN=handson.example.com",
        "Issuer": "Amazon",
        "CreatedAt": "2024-07-21T10:40:17.771000+00:00",
        "Status": "PENDING_VALIDATION",
        "KeyAlgorithm": "RSA-2048",
        "SignatureAlgorithm": "SHA256WITHRSA",
        "InUseBy": [],
        "Type": "AMAZON_ISSUED",
        "KeyUsages": [],
        "ExtendedKeyUsages": [],
        "RenewalEligibility": "INELIGIBLE",
        "Options": {
            "CertificateTransparencyLoggingPreference": "ENABLED"
        }
    }
}
```
## 証明書検証用のDNS登録 (Route53)
### レコード登録用JSON
```bash:コマンド
# 変数
VALIDATION_OPTIONS_NAME=$(
    aws acm describe-certificate \
        --region us-east-1 \
        --certificate-arn ${CERTIFICATE_ARN} \
        --query "Certificate.DomainValidationOptions[?DomainName=='${HOSTED_ZONE_NAME}'].ResourceRecord.Name" \
        --output text
) \
&& echo ${VALIDATION_OPTIONS_NAME}

VALIDATION_OPTIONS_TYPE=$(
    aws acm describe-certificate \
        --region us-east-1 \
        --certificate-arn ${CERTIFICATE_ARN} \
        --query "Certificate.DomainValidationOptions[?DomainName=='${HOSTED_ZONE_NAME}'].ResourceRecord.Type" \
        --output text
) \
&& echo ${VALIDATION_OPTIONS_TYPE}

VALIDATION_OPTIONS_VALUE=$(
    aws acm describe-certificate \
        --region us-east-1 \
        --certificate-arn ${CERTIFICATE_ARN} \
        --query "Certificate.DomainValidationOptions[?DomainName=='${HOSTED_ZONE_NAME}'].ResourceRecord.Value" \
        --output text
) \
&& echo ${VALIDATION_OPTIONS_VALUE}

# レコード登録用JSON
RECORD_JSON=$(cat << EOF
{
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "${VALIDATION_OPTIONS_NAME}",
        "Type": "${VALIDATION_OPTIONS_TYPE}",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "${VALIDATION_OPTIONS_VALUE}"
          }
        ]
      }
    }
  ]
}
EOF
) \
&& echo ${RECORD_JSON}

# JSONフォーマットの確認
echo ${RECORD_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # 変数
[cloudshell-user@ip-10-130-61-60 ~]$ VALIDATION_OPTIONS_NAME=$(
>     aws acm describe-certificate \
>         --region us-east-1 \
>         --certificate-arn ${CERTIFICATE_ARN} \
>         --query "Certificate.DomainValidationOptions[?DomainName=='${HOSTED_ZONE_NAME}'].ResourceRecord.Name" \
>         --output text
> ) \
> && echo ${VALIDATION_OPTIONS_NAME}
_e049795f32552612c6135c8d935dd7e5.handson.example.com.
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ VALIDATION_OPTIONS_TYPE=$(
>     aws acm describe-certificate \
>         --region us-east-1 \
>         --certificate-arn ${CERTIFICATE_ARN} \
>         --query "Certificate.DomainValidationOptions[?DomainName=='${HOSTED_ZONE_NAME}'].ResourceRecord.Type" \
>         --output text
> ) \
> && echo ${VALIDATION_OPTIONS_TYPE}
CNAME
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ VALIDATION_OPTIONS_VALUE=$(
>     aws acm describe-certificate \
>         --region us-east-1 \
>         --certificate-arn ${CERTIFICATE_ARN} \
>         --query "Certificate.DomainValidationOptions[?DomainName=='${HOSTED_ZONE_NAME}'].ResourceRecord.Value" \
>         --output text
> ) \
> && echo ${VALIDATION_OPTIONS_VALUE}
_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws.
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # レコード登録用JSON
[cloudshell-user@ip-10-130-61-60 ~]$ RECORD_JSON=$(cat << EOF
> {
>   "Changes": [
>     {
>       "Action": "UPSERT",
>       "ResourceRecordSet": {
>         "Name": "${VALIDATION_OPTIONS_NAME}",
>         "Type": "${VALIDATION_OPTIONS_TYPE}",
>         "TTL": 300,
>         "ResourceRecords": [
>           {
>             "Value": "${VALIDATION_OPTIONS_VALUE}"
>           }
>         ]
>       }
>     }
>   ]
> }
> EOF
> ) \
> && echo ${RECORD_JSON}
{ "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "_e049795f32552612c6135c8d935dd7e5.handson.example.com.", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws." } ] } } ] }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${RECORD_JSON} | python -m json.tool
{
    "Changes": [
        {
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": "_e049795f32552612c6135c8d935dd7e5.handson.example.com.",
                "Type": "CNAME",
                "TTL": 300,
                "ResourceRecords": [
                    {
                        "Value": "_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws."
                    }
                ]
            }
        }
    ]
}
```
### レコード作成
```bash:コマンド
# レコード作成
aws route53 change-resource-record-sets \
    --hosted-zone-id ${HOSTED_ZONE_ID} \
    --change-batch "${RECORD_JSON}"
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # レコード作成
[cloudshell-user@ip-10-130-61-60 ~]$ aws route53 change-resource-record-sets \
>     --hosted-zone-id ${HOSTED_ZONE_ID} \
>     --change-batch "${RECORD_JSON}"
{
    "ChangeInfo": {
        "Id": "/change/C07224581TG0MDCQJIMIL",
        "Status": "PENDING",
        "SubmittedAt": "2024-07-21T10:52:02.673000+00:00"
    }
}
```
## 証明書検証の確認
:::note warn
 DNSレコード登録後、"Status": "ISSUED"になるまで時間がかかる
:::
```bash:コマンド
aws acm describe-certificate \
    --certificate-arn ${CERTIFICATE_ARN} \
    --region us-east-1
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ aws acm describe-certificate \
>     --certificate-arn ${CERTIFICATE_ARN} \
>     --region us-east-1
{
    "Certificate": {
        "CertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
        "DomainName": "handson.example.com",
        "SubjectAlternativeNames": [
            "handson.example.com"
        ],
        "DomainValidationOptions": [
            {
                "DomainName": "handson.example.com",
                "ValidationDomain": "handson.example.com",
                "ValidationStatus": "SUCCESS",
                "ResourceRecord": {
                    "Name": "_e049795f32552612c6135c8d935dd7e5.handson.example.com.",
                    "Type": "CNAME",
                    "Value": "_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws."
                },
                "ValidationMethod": "DNS"
            }
        ],
        "Serial": "04:c3:b1:2b:2c:68:d4:ab:28:1f:f8:aa:f0:8e:05:3b",
        "Subject": "CN=handson.example.com",
        "Issuer": "Amazon",
        "CreatedAt": "2024-07-21T10:40:17.771000+00:00",
        "IssuedAt": "2024-07-21T10:57:36.229000+00:00",
        "Status": "ISSUED",
        "NotBefore": "2024-07-21T00:00:00+00:00",
        "NotAfter": "2025-08-19T23:59:59+00:00",
        "KeyAlgorithm": "RSA-2048",
        "SignatureAlgorithm": "SHA256WITHRSA",
        "InUseBy": [],
        "Type": "AMAZON_ISSUED",
        "KeyUsages": [
            {
                "Name": "DIGITAL_SIGNATURE"
            },
            {
                "Name": "KEY_ENCIPHERMENT"
            }
        ],
        "ExtendedKeyUsages": [
            {
                "Name": "TLS_WEB_SERVER_AUTHENTICATION",
                "OID": "1.3.6.1.5.5.7.3.1"
            },
            {
                "Name": "TLS_WEB_CLIENT_AUTHENTICATION",
                "OID": "1.3.6.1.5.5.7.3.2"
            }
        ],
        "RenewalEligibility": "INELIGIBLE",
        "Options": {
            "CertificateTransparencyLoggingPreference": "ENABLED"
        }
    }
}
```
## CloudFrontへの証明書の適用
### CloudFront設定用JSON
```bash:コマンド
# ビヘイビア設定、CNAME設定、証明書適用
CONFIG_JSON=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        | jq .DistributionConfig \
        | jq '.DefaultCacheBehavior.ViewerProtocolPolicy = "redirect-to-https"' \
        | jq --arg certArn "${CERTIFICATE_ARN}" '.ViewerCertificate |= . + {"ACMCertificateArn": $certArn, "Certificate": $certArn, "CloudFrontDefaultCertificate": false, "SSLSupportMethod": "sni-only", "MinimumProtocolVersion": "TLSv1.2_2021", "CertificateSource": "acm"}' \
        | jq --arg new_domain "${HOSTED_ZONE_NAME}" '.Aliases.Items += [$new_domain] | .Aliases.Quantity += 1'
) \
&& echo ${CONFIG_JSON}

# JSONフォーマットの確認
echo ${CONFIG_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # ビヘイビア設定、CNAME設定、証明書適用
[cloudshell-user@ip-10-130-61-60 ~]$ CONFIG_JSON=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         | jq .DistributionConfig \
>         | jq '.DefaultCacheBehavior.ViewerProtocolPolicy = "redirect-to-https"' \
>         | jq --arg certArn "${CERTIFICATE_ARN}" '.ViewerCertificate |= . + {"ACMCertificateArn": $certArn, "Certificate": $certArn, "CloudFrontDefaultCertificate": false, "SSLSupportMethod": "sni-only", "MinimumProtocolVersion": "TLSv1.2_2021", "CertificateSource": "acm"}' \
>         | jq --arg new_domain "${HOSTED_ZONE_NAME}" '.Aliases.Items += [$new_domain] | .Aliases.Quantity += 1'
> ) \
> && echo ${CONFIG_JSON}
{ "CallerReference": "cli-1721555857-121159", "Aliases": { "Quantity": 1, "Items": [ "handson.example.com" ] }, "DefaultRootObject": "", "Origins": { "Quantity": 1, "Items": [ { "Id": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971", "DomainName": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, "OriginProtocolPolicy": "http-only", "OriginSslProtocols": { "Quantity": 3, "Items": [ "TLSv1", "TLSv1.1", "TLSv1.2" ] }, "OriginReadTimeout": 30, "OriginKeepaliveTimeout": 5 }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "" } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971", "TrustedSigners": { "Enabled": false, "Quantity": 0 }, "TrustedKeyGroups": { "Enabled": false, "Quantity": 0 }, "ViewerProtocolPolicy": "redirect-to-https", "AllowedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ], "CachedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ] } }, "SmoothStreaming": false, "Compress": false, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "ForwardedValues": { "QueryString": false, "Cookies": { "Forward": "none" }, "Headers": { "Quantity": 0 }, "QueryStringCacheKeys": { "Quantity": 0 } }, "MinTTL": 0, "DefaultTTL": 86400, "MaxTTL": 31536000 }, "CacheBehaviors": { "Quantity": 0 }, "CustomErrorResponses": { "Quantity": 0 }, "Comment": "", "Logging": { "Enabled": false, "IncludeCookies": false, "Bucket": "", "Prefix": "" }, "PriceClass": "PriceClass_All", "Enabled": true, "ViewerCertificate": { "CloudFrontDefaultCertificate": false, "SSLSupportMethod": "sni-only", "MinimumProtocolVersion": "TLSv1.2_2021", "CertificateSource": "acm", "ACMCertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56", "Certificate": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56" }, "Restrictions": { "GeoRestriction": { "RestrictionType": "none", "Quantity": 0 } }, "WebACLId": "", "HttpVersion": "http2", "IsIPV6Enabled": true, "ContinuousDeploymentPolicyId": "", "Staging": false }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${CONFIG_JSON} | python -m json.tool
{
    "CallerReference": "cli-1721555857-121159",
    "Aliases": {
        "Quantity": 1,
        "Items": [
            "handson.example.com"
        ]
    },
    "DefaultRootObject": "",
    "Origins": {
        "Quantity": 1,
        "Items": [
            {
                "Id": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                "DomainName": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "CustomOriginConfig": {
                    "HTTPPort": 80,
                    "HTTPSPort": 443,
                    "OriginProtocolPolicy": "http-only",
                    "OriginSslProtocols": {
                        "Quantity": 3,
                        "Items": [
                            "TLSv1",
                            "TLSv1.1",
                            "TLSv1.2"
                        ]
                    },
                    "OriginReadTimeout": 30,
                    "OriginKeepaliveTimeout": 5
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": ""
            }
        ]
    },
    "OriginGroups": {
        "Quantity": 0
    },
    "DefaultCacheBehavior": {
        "TargetOriginId": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
        "TrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "TrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "ViewerProtocolPolicy": "redirect-to-https",
        "AllowedMethods": {
            "Quantity": 2,
            "Items": [
                "HEAD",
                "GET"
            ],
            "CachedMethods": {
                "Quantity": 2,
                "Items": [
                    "HEAD",
                    "GET"
                ]
            }
        },
        "SmoothStreaming": false,
        "Compress": false,
        "LambdaFunctionAssociations": {
            "Quantity": 0
        },
        "FunctionAssociations": {
            "Quantity": 0
        },
        "FieldLevelEncryptionId": "",
        "ForwardedValues": {
            "QueryString": false,
            "Cookies": {
                "Forward": "none"
            },
            "Headers": {
                "Quantity": 0
            },
            "QueryStringCacheKeys": {
                "Quantity": 0
            }
        },
        "MinTTL": 0,
        "DefaultTTL": 86400,
        "MaxTTL": 31536000
    },
    "CacheBehaviors": {
        "Quantity": 0
    },
    "CustomErrorResponses": {
        "Quantity": 0
    },
    "Comment": "",
    "Logging": {
        "Enabled": false,
        "IncludeCookies": false,
        "Bucket": "",
        "Prefix": ""
    },
    "PriceClass": "PriceClass_All",
    "Enabled": true,
    "ViewerCertificate": {
        "CloudFrontDefaultCertificate": false,
        "SSLSupportMethod": "sni-only",
        "MinimumProtocolVersion": "TLSv1.2_2021",
        "CertificateSource": "acm",
        "ACMCertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
        "Certificate": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56"
    },
    "Restrictions": {
        "GeoRestriction": {
            "RestrictionType": "none",
            "Quantity": 0
        }
    },
    "WebACLId": "",
    "HttpVersion": "http2",
    "IsIPV6Enabled": true,
    "ContinuousDeploymentPolicyId": "",
    "Staging": false
}
```
### CloudFrontディストリビューションの設定を更新
```bash:コマンド
# ETagを取得
ETAG=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        --query ETag \
        --output text
) \
&& echo ${ETAG}

# CloudFrontディストリビューションの設定を更新
aws cloudfront update-distribution \
    --id ${DISTRIBUTION_ID} \
    --distribution-config "${CONFIG_JSON}" \
    --if-match ${ETAG}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # ETagを取得
[cloudshell-user@ip-10-130-61-60 ~]$ ETAG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
E95HZYNGU9MLI
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # CloudFrontディストリビューションの設定を更新
[cloudshell-user@ip-10-130-61-60 ~]$ aws cloudfront update-distribution \
>     --id ${DISTRIBUTION_ID} \
>     --distribution-config "${CONFIG_JSON}" \
>     --if-match ${ETAG}
{
    "ETag": "EO48TEFCWS75N",
    "Distribution": {
        "Id": "E4GYIQL4T0TP0",
        "ARN": "arn:aws:cloudfront::999999999999:distribution/E4GYIQL4T0TP0",
        "Status": "InProgress",
        "LastModifiedTime": "2024-07-21T11:32:31.733000+00:00",
        "InProgressInvalidationBatches": 0,
        "DomainName": "d2xpr76fxshx5q.cloudfront.net",
        "ActiveTrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ActiveTrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "DistributionConfig": {
            "CallerReference": "cli-1721555857-121159",
            "Aliases": {
                "Quantity": 1,
                "Items": [
                    "handson.example.com"
                ]
            },
            "DefaultRootObject": "",
            "Origins": {
                "Quantity": 1,
                "Items": [
                    {
                        "Id": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                        "DomainName": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "CustomOriginConfig": {
                            "HTTPPort": 80,
                            "HTTPSPort": 443,
                            "OriginProtocolPolicy": "http-only",
                            "OriginSslProtocols": {
                                "Quantity": 3,
                                "Items": [
                                    "TLSv1",
                                    "TLSv1.1",
                                    "TLSv1.2"
                                ]
                            },
                            "OriginReadTimeout": 30,
                            "OriginKeepaliveTimeout": 5
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": ""
                    }
                ]
            },
            "OriginGroups": {
                "Quantity": 0
            },
            "DefaultCacheBehavior": {
                "TargetOriginId": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                "TrustedSigners": {
                    "Enabled": false,
                    "Quantity": 0
                },
                "TrustedKeyGroups": {
                    "Enabled": false,
                    "Quantity": 0
                },
                "ViewerProtocolPolicy": "redirect-to-https",
                "AllowedMethods": {
                    "Quantity": 2,
                    "Items": [
                        "HEAD",
                        "GET"
                    ],
                    "CachedMethods": {
                        "Quantity": 2,
                        "Items": [
                            "HEAD",
                            "GET"
                        ]
                    }
                },
                "SmoothStreaming": false,
                "Compress": false,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "ForwardedValues": {
                    "QueryString": false,
                    "Cookies": {
                        "Forward": "none"
                    },
                    "Headers": {
                        "Quantity": 0
                    },
                    "QueryStringCacheKeys": {
                        "Quantity": 0
                    }
                },
                "MinTTL": 0,
                "DefaultTTL": 86400,
                "MaxTTL": 31536000
            },
            "CacheBehaviors": {
                "Quantity": 0
            },
            "CustomErrorResponses": {
                "Quantity": 0
            },
            "Comment": "",
            "Logging": {
                "Enabled": false,
                "IncludeCookies": false,
                "Bucket": "",
                "Prefix": ""
            },
            "PriceClass": "PriceClass_All",
            "Enabled": true,
            "ViewerCertificate": {
                "CloudFrontDefaultCertificate": false,
                "ACMCertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
                "SSLSupportMethod": "sni-only",
                "MinimumProtocolVersion": "TLSv1.2_2021",
                "Certificate": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
                "CertificateSource": "acm"
            },
            "Restrictions": {
                "GeoRestriction": {
                    "RestrictionType": "none",
                    "Quantity": 0
                }
            },
            "WebACLId": "",
            "HttpVersion": "http2",
            "IsIPV6Enabled": true,
            "ContinuousDeploymentPolicyId": "",
            "Staging": false
        },
        "AliasICPRecordals": [
            {
                "CNAME": "handson.example.com",
                "ICPRecordalStatus": "APPROVED"
            }
        ]
    }
}
```
## DNSの向き先をCloudFrontに変更
### レコード登録用JSON
:::note alert
"HostedZoneId": "Z2FDTNDATAQYW2",  # CloudFrontのホストゾーンID
:::
```bash:コマンド
# レコード登録用JSON
RECORD_JSON=$(cat << EOF
{
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "${HOSTED_ZONE_NAME}",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "DNSName": "${DISTRIBUTION_DOMAINNAME}.",
          "EvaluateTargetHealth": true
        }
      }
    }
  ]
}
EOF
) \
&& echo ${RECORD_JSON}

# JSONフォーマットの確認
echo ${RECORD_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # レコード登録用JSON
[cloudshell-user@ip-10-130-61-60 ~]$ RECORD_JSON=$(cat << EOF
> {
>   "Changes": [
>     {
>       "Action": "UPSERT",
>       "ResourceRecordSet": {
>         "Name": "${HOSTED_ZONE_NAME}",
>         "Type": "A",
>         "AliasTarget": {
>           "HostedZoneId": "Z2FDTNDATAQYW2",
>           "DNSName": "${DISTRIBUTION_DOMAINNAME}.",
>           "EvaluateTargetHealth": true
>         }
>       }
>     }
>   ]
> }
> EOF
> ) \
> && echo ${RECORD_JSON}
{ "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "handson.example.com", "Type": "A", "AliasTarget": { "HostedZoneId": "Z2FDTNDATAQYW2", "DNSName": "d2xpr76fxshx5q.cloudfront.net.", "EvaluateTargetHealth": true } } } ] }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${RECORD_JSON} | python -m json.tool
{
    "Changes": [
        {
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": "handson.example.com",
                "Type": "A",
                "AliasTarget": {
                    "HostedZoneId": "Z2FDTNDATAQYW2",
                    "DNSName": "d2xpr76fxshx5q.cloudfront.net.",
                    "EvaluateTargetHealth": true
                }
            }
        }
    ]
}
```
### レコード登録
```bash:コマンド
# レコード登録
aws route53 change-resource-record-sets \
    --hosted-zone-id ${HOSTED_ZONE_ID} \
    --change-batch "${RECORD_JSON}"
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # レコード登録
[cloudshell-user@ip-10-130-61-60 ~]$ aws route53 change-resource-record-sets \
>     --hosted-zone-id ${HOSTED_ZONE_ID} \
>     --change-batch "${RECORD_JSON}"
{
    "ChangeInfo": {
        "Id": "/change/C09392093S1UD5VZ0Z50C",
        "Status": "PENDING",
        "SubmittedAt": "2024-07-21T11:36:23.424000+00:00"
    }
}
```
### アクセス確認 (https)
```bash:コマンド
curl https://handson.example.com/
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ curl https://handson.example.com/
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての AWS</title>
  <link rel="icon" href="favicon.ico">
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div>
  　<div class="icon">
      <img src="img/lambda.png">
    </div>
    <div class="msg">
      このページでは、AWS について学んだことを書いていきます。
    </div>
  </div>
</body>
</html>
```
### アクセス確認 (http)
```bash:コマンド
curl http://handson.example.com/
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ curl http://handson.example.com/
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>CloudFront</center>
</body>
</html>
```
## S3への直接アクセス禁止
### S3設定変更
```bash:コマンド
# バケットポリシー削除
aws s3api delete-bucket-policy \
    --bucket ${S3_BUCKET_NAME}

# 静的ホスティング無効化
aws s3api delete-bucket-website \
    --bucket ${S3_BUCKET_NAME}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # バケットポリシー削除
[cloudshell-user@ip-10-130-61-60 ~]$ aws s3api delete-bucket-policy \
>     --bucket ${S3_BUCKET_NAME}
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # 静的ホスティング無効化
[cloudshell-user@ip-10-130-61-60 ~]$ aws s3api delete-bucket-website \
>     --bucket ${S3_BUCKET_NAME}
```
## CloudFrontオリジンアクセス作成
### オリジンアクセス用JSON
```bash:コマンド
# オリジンアクセス用JSON
ORIGIN_ACCESS_JSON=$(cat << EOF
{
    "Name": "${HOSTED_ZONE_NAME}.s3.ap-northeast-1.amazonaws.com",
    "SigningProtocol": "sigv4",
    "SigningBehavior": "always",
    "OriginAccessControlOriginType": "s3"
}
EOF
) \
&& echo ${ORIGIN_ACCESS_JSON}

# JSONフォーマットの確認
echo ${ORIGIN_ACCESS_JSON} | python -m json.tool
```
```bash:出力
cloudshell-user@ip-10-130-61-60 ~]$ # オリジンアクセス用JSON
[cloudshell-user@ip-10-130-61-60 ~]$ ORIGIN_ACCESS_JSON=$(cat << EOF
> {
>     "Name": "${HOSTED_ZONE_NAME}.s3.ap-northeast-1.amazonaws.com",
>     "SigningProtocol": "sigv4",
>     "SigningBehavior": "always",
>     "OriginAccessControlOriginType": "s3"
> }
> EOF
> ) \
> && echo ${ORIGIN_ACCESS_JSON}
{ "Name": "handson.example.com.s3.ap-northeast-1.amazonaws.com", "SigningProtocol": "sigv4", "SigningBehavior": "always", "OriginAccessControlOriginType": "s3" }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${ORIGIN_ACCESS_JSON} | python -m json.tool
{
    "Name": "handson.example.com.s3.ap-northeast-1.amazonaws.com",
    "SigningProtocol": "sigv4",
    "SigningBehavior": "always",
    "OriginAccessControlOriginType": "s3"
}
```
### オリジンアクセス作成
```bash:コマンド
# 作成
aws cloudfront create-origin-access-control \
    --origin-access-control-config "${ORIGIN_ACCESS_JSON}"

# ID取得
ORIGIN_ACCESS_CONTROL_ID=$(
    aws cloudfront list-origin-access-controls \
        --query "OriginAccessControlList.Items[?Name=='${HOSTED_ZONE_NAME}.s3.ap-northeast-1.amazonaws.com'].Id" \
        --output text
) \
&& echo ${ORIGIN_ACCESS_CONTROL_ID} 
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # 作成
[cloudshell-user@ip-10-130-61-60 ~]$ aws cloudfront create-origin-access-control \
>     --origin-access-control-config "${ORIGIN_ACCESS_JSON}"
{
    "Location": "https://cloudfront.amazonaws.com/2020-05-31/origin-access-control/E1BJDY9OECT8GB",
    "ETag": "ETVPDKIKX0DER",
    "OriginAccessControl": {
        "Id": "E1BJDY9OECT8GB",
        "OriginAccessControlConfig": {
            "Name": "handson.example.com.s3.ap-northeast-1.amazonaws.com",
            "SigningProtocol": "sigv4",
            "SigningBehavior": "always",
            "OriginAccessControlOriginType": "s3"
        }
    }
}
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # ID取得
[cloudshell-user@ip-10-130-61-60 ~]$ ORIGIN_ACCESS_CONTROL_ID=$(
>     aws cloudfront list-origin-access-controls \
>         --query "OriginAccessControlList.Items[?Name=='${HOSTED_ZONE_NAME}.s3.ap-northeast-1.amazonaws.com'].Id" \
>         --output text
> ) \
> && echo ${ORIGIN_ACCESS_CONTROL_ID} 
E1BJDY9OECT8GB
```
### S3 オリジンアクセス用バケットポリシーJSON
```bash:コマンド
# バケットポリシー(JSON)
BACKET_POLICY=$(cat << EOF
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "${DISTRIBUTION_ARN}"
                }
            }
        }
    ]
}
EOF
) \
&& echo ${BACKET_POLICY}

# JSONフォーマットの確認
echo ${BACKET_POLICY} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # バケットポリシー(JSON)
[cloudshell-user@ip-10-130-61-60 ~]$ BACKET_POLICY=$(cat << EOF
> {
>     "Version": "2008-10-17",
>     "Id": "PolicyForCloudFrontPrivateContent",
>     "Statement": [
>         {
>             "Sid": "AllowCloudFrontServicePrincipal",
>             "Effect": "Allow",
>             "Principal": {
>                 "Service": "cloudfront.amazonaws.com"
>             },
>             "Action": "s3:GetObject",
>             "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}/*",
>             "Condition": {
>                 "StringEquals": {
>                     "AWS:SourceArn": "${DISTRIBUTION_ARN}"
>                 }
>             }
>         }
>     ]
> }
> EOF
> ) \
> && echo ${BACKET_POLICY}
{ "Version": "2008-10-17", "Id": "PolicyForCloudFrontPrivateContent", "Statement": [ { "Sid": "AllowCloudFrontServicePrincipal", "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::handson.example.com/*", "Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::999999999999:distribution/E4GYIQL4T0TP0" } } } ] }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${BACKET_POLICY} | python -m json.tool
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::handson.example.com/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::999999999999:distribution/E4GYIQL4T0TP0"
                }
            }
        }
    ]
}
```
### S3 オリジンアクセス用バケットポリシー適用
```bash:コマンド
# バケットポリシー
aws s3api put-bucket-policy \
    --bucket ${S3_BUCKET_NAME} \
    --policy "${BACKET_POLICY}"
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # バケットポリシー
[cloudshell-user@ip-10-130-61-60 ~]$ aws s3api put-bucket-policy \
>     --bucket ${S3_BUCKET_NAME} \
>     --policy "${BACKET_POLICY}"
```
### CloudFrontオリジンドメイン用JSON
```bash:コマンド
# CloudFrontオリジンドメイン用JSON
CONFIG_JSON=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        | jq .DistributionConfig \
        | jq --arg new_domain "${HOSTED_ZONE_NAME}.s3.ap-northeast-1.amazonaws.com" '.Origins.Items.[].DomainName = $new_domain' \
        | jq 'del(.Origins.Items[].CustomOriginConfig)' \
        | jq '.Origins.Items[].S3OriginConfig = {"OriginAccessIdentity": ""}' \
        | jq --arg originId "${ORIGIN_ACCESS_CONTROL_ID}" '.Origins.Items.[].OriginAccessControlId = $originId'
) \
&& echo ${CONFIG_JSON}

# JSONフォーマットの確認
echo ${CONFIG_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # CloudFrontオリジンドメイン用JSON
[cloudshell-user@ip-10-130-61-60 ~]$ CONFIG_JSON=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         | jq .DistributionConfig \
>         | jq --arg new_domain "${HOSTED_ZONE_NAME}.s3.ap-northeast-1.amazonaws.com" '.Origins.Items.[].DomainName = $new_domain' \
>         | jq 'del(.Origins.Items[].CustomOriginConfig)' \
>         | jq '.Origins.Items[].S3OriginConfig = {"OriginAccessIdentity": ""}' \
>         | jq --arg originId "${ORIGIN_ACCESS_CONTROL_ID}" '.Origins.Items.[].OriginAccessControlId = $originId'
> ) \
> && echo ${CONFIG_JSON}
{ "CallerReference": "cli-1721555857-121159", "Aliases": { "Quantity": 1, "Items": [ "handson.example.com" ] }, "DefaultRootObject": "", "Origins": { "Quantity": 1, "Items": [ { "Id": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971", "DomainName": "handson.example.com.s3.ap-northeast-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "E1BJDY9OECT8GB", "S3OriginConfig": { "OriginAccessIdentity": "" } } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971", "TrustedSigners": { "Enabled": false, "Quantity": 0 }, "TrustedKeyGroups": { "Enabled": false, "Quantity": 0 }, "ViewerProtocolPolicy": "redirect-to-https", "AllowedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ], "CachedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ] } }, "SmoothStreaming": false, "Compress": false, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "ForwardedValues": { "QueryString": false, "Cookies": { "Forward": "none" }, "Headers": { "Quantity": 0 }, "QueryStringCacheKeys": { "Quantity": 0 } }, "MinTTL": 0, "DefaultTTL": 86400, "MaxTTL": 31536000 }, "CacheBehaviors": { "Quantity": 0 }, "CustomErrorResponses": { "Quantity": 0 }, "Comment": "", "Logging": { "Enabled": false, "IncludeCookies": false, "Bucket": "", "Prefix": "" }, "PriceClass": "PriceClass_All", "Enabled": true, "ViewerCertificate": { "CloudFrontDefaultCertificate": false, "ACMCertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56", "SSLSupportMethod": "sni-only", "MinimumProtocolVersion": "TLSv1.2_2021", "Certificate": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56", "CertificateSource": "acm" }, "Restrictions": { "GeoRestriction": { "RestrictionType": "none", "Quantity": 0 } }, "WebACLId": "", "HttpVersion": "http2", "IsIPV6Enabled": true, "ContinuousDeploymentPolicyId": "", "Staging": false }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${CONFIG_JSON} | python -m json.tool
{
    "CallerReference": "cli-1721555857-121159",
    "Aliases": {
        "Quantity": 1,
        "Items": [
            "handson.example.com"
        ]
    },
    "DefaultRootObject": "",
    "Origins": {
        "Quantity": 1,
        "Items": [
            {
                "Id": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                "DomainName": "handson.example.com.s3.ap-northeast-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": "E1BJDY9OECT8GB",
                "S3OriginConfig": {
                    "OriginAccessIdentity": ""
                }
            }
        ]
    },
    "OriginGroups": {
        "Quantity": 0
    },
    "DefaultCacheBehavior": {
        "TargetOriginId": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
        "TrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "TrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "ViewerProtocolPolicy": "redirect-to-https",
        "AllowedMethods": {
            "Quantity": 2,
            "Items": [
                "HEAD",
                "GET"
            ],
            "CachedMethods": {
                "Quantity": 2,
                "Items": [
                    "HEAD",
                    "GET"
                ]
            }
        },
        "SmoothStreaming": false,
        "Compress": false,
        "LambdaFunctionAssociations": {
            "Quantity": 0
        },
        "FunctionAssociations": {
            "Quantity": 0
        },
        "FieldLevelEncryptionId": "",
        "ForwardedValues": {
            "QueryString": false,
            "Cookies": {
                "Forward": "none"
            },
            "Headers": {
                "Quantity": 0
            },
            "QueryStringCacheKeys": {
                "Quantity": 0
            }
        },
        "MinTTL": 0,
        "DefaultTTL": 86400,
        "MaxTTL": 31536000
    },
    "CacheBehaviors": {
        "Quantity": 0
    },
    "CustomErrorResponses": {
        "Quantity": 0
    },
    "Comment": "",
    "Logging": {
        "Enabled": false,
        "IncludeCookies": false,
        "Bucket": "",
        "Prefix": ""
    },
    "PriceClass": "PriceClass_All",
    "Enabled": true,
    "ViewerCertificate": {
        "CloudFrontDefaultCertificate": false,
        "ACMCertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
        "SSLSupportMethod": "sni-only",
        "MinimumProtocolVersion": "TLSv1.2_2021",
        "Certificate": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
        "CertificateSource": "acm"
    },
    "Restrictions": {
        "GeoRestriction": {
            "RestrictionType": "none",
            "Quantity": 0
        }
    },
    "WebACLId": "",
    "HttpVersion": "http2",
    "IsIPV6Enabled": true,
    "ContinuousDeploymentPolicyId": "",
    "Staging": false
}
```
### CloudFrontオリジンドメイン適用
```bash:コマンド
# ETagを取得
ETAG=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        --query ETag \
        --output text
) \
&& echo ${ETAG}

# CloudFrontディストリビューションの設定を更新
aws cloudfront update-distribution \
    --id ${DISTRIBUTION_ID} \
    --distribution-config "${CONFIG_JSON}" \
    --if-match ${ETAG}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # ETagを取得
[cloudshell-user@ip-10-130-61-60 ~]$ ETAG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
E3IIY12J06X0JQ
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # CloudFrontディストリビューションの設定を更新
[cloudshell-user@ip-10-130-61-60 ~]$ aws cloudfront update-distribution \
>     --id ${DISTRIBUTION_ID} \
>     --distribution-config "${CONFIG_JSON}" \
>     --if-match ${ETAG}
{
    "ETag": "E2WT6WS7I8YN8T",
    "Distribution": {
        "Id": "E4GYIQL4T0TP0",
        "ARN": "arn:aws:cloudfront::999999999999:distribution/E4GYIQL4T0TP0",
        "Status": "InProgress",
        "LastModifiedTime": "2024-07-21T12:26:44.447000+00:00",
        "InProgressInvalidationBatches": 0,
        "DomainName": "d2xpr76fxshx5q.cloudfront.net",
        "ActiveTrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ActiveTrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "DistributionConfig": {
            "CallerReference": "cli-1721555857-121159",
            "Aliases": {
                "Quantity": 1,
                "Items": [
                    "handson.example.com"
                ]
            },
            "DefaultRootObject": "",
            "Origins": {
                "Quantity": 1,
                "Items": [
                    {
                        "Id": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                        "DomainName": "handson.example.com.s3.ap-northeast-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "S3OriginConfig": {
                            "OriginAccessIdentity": ""
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": "E1BJDY9OECT8GB"
                    }
                ]
            },
            "OriginGroups": {
                "Quantity": 0
            },
            "DefaultCacheBehavior": {
                "TargetOriginId": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                "TrustedSigners": {
                    "Enabled": false,
                    "Quantity": 0
                },
                "TrustedKeyGroups": {
                    "Enabled": false,
                    "Quantity": 0
                },
                "ViewerProtocolPolicy": "redirect-to-https",
                "AllowedMethods": {
                    "Quantity": 2,
                    "Items": [
                        "HEAD",
                        "GET"
                    ],
                    "CachedMethods": {
                        "Quantity": 2,
                        "Items": [
                            "HEAD",
                            "GET"
                        ]
                    }
                },
                "SmoothStreaming": false,
                "Compress": false,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "ForwardedValues": {
                    "QueryString": false,
                    "Cookies": {
                        "Forward": "none"
                    },
                    "Headers": {
                        "Quantity": 0
                    },
                    "QueryStringCacheKeys": {
                        "Quantity": 0
                    }
                },
                "MinTTL": 0,
                "DefaultTTL": 86400,
                "MaxTTL": 31536000
            },
            "CacheBehaviors": {
                "Quantity": 0
            },
            "CustomErrorResponses": {
                "Quantity": 0
            },
            "Comment": "",
            "Logging": {
                "Enabled": false,
                "IncludeCookies": false,
                "Bucket": "",
                "Prefix": ""
            },
            "PriceClass": "PriceClass_All",
            "Enabled": true,
            "ViewerCertificate": {
                "CloudFrontDefaultCertificate": false,
                "ACMCertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
                "SSLSupportMethod": "sni-only",
                "MinimumProtocolVersion": "TLSv1.2_2021",
                "Certificate": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
                "CertificateSource": "acm"
            },
            "Restrictions": {
                "GeoRestriction": {
                    "RestrictionType": "none",
                    "Quantity": 0
                }
            },
            "WebACLId": "",
            "HttpVersion": "http2",
            "IsIPV6Enabled": true,
            "ContinuousDeploymentPolicyId": "",
            "Staging": false
        },
        "AliasICPRecordals": [
            {
                "CNAME": "handson.example.com",
                "ICPRecordalStatus": "APPROVED"
            }
        ]
    }
}
```
### アクセス確認 (S3)
```bash:コマンド
curl http://handson.example.com.s3-website-ap-northeast-1.amazonaws.com//
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ curl http://handson.example.com.s3-website-ap-northeast-1.amazonaws.com//
<html>
<head><title>404 Not Found</title></head>
<body>
<h1>404 Not Found</h1>
<ul>
<li>Code: NoSuchWebsiteConfiguration</li>
<li>Message: The specified bucket does not have a website configuration</li>
<li>BucketName: handson.example.com</li>
<li>RequestId: YZT6SA38C2HSMA89</li>
<li>HostId: CR5DgqQYM/MbOCmLkCUynwGTqnvH2MCNKEI08vHz3Ol/MUzVtAWPkbtlEiy+Q7OshtziSqq0hKs=</li>
</ul>
<hr/>
</body>
</html>
```
### アクセス確認 (CloudFront)
```bash:コマンド
curl https://handson.example.com/
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ curl https://handson.example.com/
<!DOCTYPE html>

<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>はじめての AWS</title>
  <link rel="icon" href="favicon.ico">
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div>
  　<div class="icon">
      <img src="img/lambda.png">
    </div>
    <div class="msg">
      このページでは、AWS について学んだことを書いていきます。
    </div>
  </div>
</body>
</html>
```
# 7. 削除
## CloudFront
### ディストリビューション無効化用JSON
```bash:コマンド
# ディストリビューション無効化用JSON
DELL_CONFIG=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        | jq .DistributionConfig \
        | jq '.Enabled = false'
) \
&& echo ${DELL_CONFIG}

# JSONフォーマットの確認
echo ${DELL_CONFIG} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # ディストリビューション無効化用JSON
[cloudshell-user@ip-10-130-61-60 ~]$ DELL_CONFIG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         | jq .DistributionConfig \
>         | jq '.Enabled = false'
> ) \
> && echo ${DELL_CONFIG}
{ "CallerReference": "cli-1721555857-121159", "Aliases": { "Quantity": 1, "Items": [ "handson.example.com" ] }, "DefaultRootObject": "", "Origins": { "Quantity": 1, "Items": [ { "Id": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971", "DomainName": "handson.example.com.s3.ap-northeast-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "S3OriginConfig": { "OriginAccessIdentity": "" }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "E1BJDY9OECT8GB" } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971", "TrustedSigners": { "Enabled": false, "Quantity": 0 }, "TrustedKeyGroups": { "Enabled": false, "Quantity": 0 }, "ViewerProtocolPolicy": "redirect-to-https", "AllowedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ], "CachedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ] } }, "SmoothStreaming": false, "Compress": false, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "ForwardedValues": { "QueryString": false, "Cookies": { "Forward": "none" }, "Headers": { "Quantity": 0 }, "QueryStringCacheKeys": { "Quantity": 0 } }, "MinTTL": 0, "DefaultTTL": 86400, "MaxTTL": 31536000 }, "CacheBehaviors": { "Quantity": 0 }, "CustomErrorResponses": { "Quantity": 0 }, "Comment": "", "Logging": { "Enabled": false, "IncludeCookies": false, "Bucket": "", "Prefix": "" }, "PriceClass": "PriceClass_All", "Enabled": false, "ViewerCertificate": { "CloudFrontDefaultCertificate": false, "ACMCertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56", "SSLSupportMethod": "sni-only", "MinimumProtocolVersion": "TLSv1.2_2021", "Certificate": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56", "CertificateSource": "acm" }, "Restrictions": { "GeoRestriction": { "RestrictionType": "none", "Quantity": 0 } }, "WebACLId": "", "HttpVersion": "http2", "IsIPV6Enabled": true, "ContinuousDeploymentPolicyId": "", "Staging": false }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${DELL_CONFIG} | python -m json.tool
{
    "CallerReference": "cli-1721555857-121159",
    "Aliases": {
        "Quantity": 1,
        "Items": [
            "handson.example.com"
        ]
    },
    "DefaultRootObject": "",
    "Origins": {
        "Quantity": 1,
        "Items": [
            {
                "Id": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                "DomainName": "handson.example.com.s3.ap-northeast-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "S3OriginConfig": {
                    "OriginAccessIdentity": ""
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": "E1BJDY9OECT8GB"
            }
        ]
    },
    "OriginGroups": {
        "Quantity": 0
    },
    "DefaultCacheBehavior": {
        "TargetOriginId": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
        "TrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "TrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "ViewerProtocolPolicy": "redirect-to-https",
        "AllowedMethods": {
            "Quantity": 2,
            "Items": [
                "HEAD",
                "GET"
            ],
            "CachedMethods": {
                "Quantity": 2,
                "Items": [
                    "HEAD",
                    "GET"
                ]
            }
        },
        "SmoothStreaming": false,
        "Compress": false,
        "LambdaFunctionAssociations": {
            "Quantity": 0
        },
        "FunctionAssociations": {
            "Quantity": 0
        },
        "FieldLevelEncryptionId": "",
        "ForwardedValues": {
            "QueryString": false,
            "Cookies": {
                "Forward": "none"
            },
            "Headers": {
                "Quantity": 0
            },
            "QueryStringCacheKeys": {
                "Quantity": 0
            }
        },
        "MinTTL": 0,
        "DefaultTTL": 86400,
        "MaxTTL": 31536000
    },
    "CacheBehaviors": {
        "Quantity": 0
    },
    "CustomErrorResponses": {
        "Quantity": 0
    },
    "Comment": "",
    "Logging": {
        "Enabled": false,
        "IncludeCookies": false,
        "Bucket": "",
        "Prefix": ""
    },
    "PriceClass": "PriceClass_All",
    "Enabled": false,
    "ViewerCertificate": {
        "CloudFrontDefaultCertificate": false,
        "ACMCertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
        "SSLSupportMethod": "sni-only",
        "MinimumProtocolVersion": "TLSv1.2_2021",
        "Certificate": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
        "CertificateSource": "acm"
    },
    "Restrictions": {
        "GeoRestriction": {
            "RestrictionType": "none",
            "Quantity": 0
        }
    },
    "WebACLId": "",
    "HttpVersion": "http2",
    "IsIPV6Enabled": true,
    "ContinuousDeploymentPolicyId": "",
    "Staging": false
}
```
### ディストリビューション無効化
```bash:コマンド
# ETagを取得
ETAG=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        --query ETag \
        --output text
) \
&& echo ${ETAG}

# ディストリビューションを無効化
aws cloudfront update-distribution \
    --id ${DISTRIBUTION_ID} \
    --distribution-config "${DELL_CONFIG}" \
    --if-match ${ETAG}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # ETagを取得
[cloudshell-user@ip-10-130-61-60 ~]$ ETAG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
E2WT6WS7I8YN8T
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # ディストリビューションを無効化
[cloudshell-user@ip-10-130-61-60 ~]$ aws cloudfront update-distribution \
>     --id ${DISTRIBUTION_ID} \
>     --distribution-config "${DELL_CONFIG}" \
>     --if-match ${ETAG}
{
    "ETag": "E1STJVVBU7V2HO",
    "Distribution": {
        "Id": "E4GYIQL4T0TP0",
        "ARN": "arn:aws:cloudfront::999999999999:distribution/E4GYIQL4T0TP0",
        "Status": "InProgress",
        "LastModifiedTime": "2024-07-21T12:39:01.911000+00:00",
        "InProgressInvalidationBatches": 0,
        "DomainName": "d2xpr76fxshx5q.cloudfront.net",
        "ActiveTrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ActiveTrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "DistributionConfig": {
            "CallerReference": "cli-1721555857-121159",
            "Aliases": {
                "Quantity": 1,
                "Items": [
                    "handson.example.com"
                ]
            },
            "DefaultRootObject": "",
            "Origins": {
                "Quantity": 1,
                "Items": [
                    {
                        "Id": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                        "DomainName": "handson.example.com.s3.ap-northeast-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "S3OriginConfig": {
                            "OriginAccessIdentity": ""
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": "E1BJDY9OECT8GB"
                    }
                ]
            },
            "OriginGroups": {
                "Quantity": 0
            },
            "DefaultCacheBehavior": {
                "TargetOriginId": "handson.example.com.s3-website-ap-northeast-1.amazonaws.com-1721555857-565971",
                "TrustedSigners": {
                    "Enabled": false,
                    "Quantity": 0
                },
                "TrustedKeyGroups": {
                    "Enabled": false,
                    "Quantity": 0
                },
                "ViewerProtocolPolicy": "redirect-to-https",
                "AllowedMethods": {
                    "Quantity": 2,
                    "Items": [
                        "HEAD",
                        "GET"
                    ],
                    "CachedMethods": {
                        "Quantity": 2,
                        "Items": [
                            "HEAD",
                            "GET"
                        ]
                    }
                },
                "SmoothStreaming": false,
                "Compress": false,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "ForwardedValues": {
                    "QueryString": false,
                    "Cookies": {
                        "Forward": "none"
                    },
                    "Headers": {
                        "Quantity": 0
                    },
                    "QueryStringCacheKeys": {
                        "Quantity": 0
                    }
                },
                "MinTTL": 0,
                "DefaultTTL": 86400,
                "MaxTTL": 31536000
            },
            "CacheBehaviors": {
                "Quantity": 0
            },
            "CustomErrorResponses": {
                "Quantity": 0
            },
            "Comment": "",
            "Logging": {
                "Enabled": false,
                "IncludeCookies": false,
                "Bucket": "",
                "Prefix": ""
            },
            "PriceClass": "PriceClass_All",
            "Enabled": false,
            "ViewerCertificate": {
                "CloudFrontDefaultCertificate": false,
                "ACMCertificateArn": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
                "SSLSupportMethod": "sni-only",
                "MinimumProtocolVersion": "TLSv1.2_2021",
                "Certificate": "arn:aws:acm:us-east-1:999999999999:certificate/ff02e147-6b72-4856-916c-fc0dcb5c6a56",
                "CertificateSource": "acm"
            },
            "Restrictions": {
                "GeoRestriction": {
                    "RestrictionType": "none",
                    "Quantity": 0
                }
            },
            "WebACLId": "",
            "HttpVersion": "http2",
            "IsIPV6Enabled": true,
            "ContinuousDeploymentPolicyId": "",
            "Staging": false
        },
        "AliasICPRecordals": [
            {
                "CNAME": "handson.example.com",
                "ICPRecordalStatus": "APPROVED"
            }
        ]
    }
}
```
### ディストリビューション削除
```bash:コマンド
# ETagを取得
ETAG=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        --query ETag \
        --output text
) \
&& echo ${ETAG}

# ディストリビューションを削除
aws cloudfront delete-distribution \
    --id ${DISTRIBUTION_ID} \
    --if-match ${ETAG}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # ETagを取得
[cloudshell-user@ip-10-130-61-60 ~]$ ETAG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
E1STJVVBU7V2HO
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # ディストリビューションを削除
[cloudshell-user@ip-10-130-61-60 ~]$ aws cloudfront delete-distribution \
>     --id ${DISTRIBUTION_ID} \
>     --if-match ${ETAG}
```
### オリジンアクセス削除
```bash:コマンド
# ETagを取得
ETAG=$(
    aws cloudfront get-origin-access-control \
        --id ${ORIGIN_ACCESS_CONTROL_ID} \
        --query ETag \
        --output text
) \
&& echo ${ETAG}

aws cloudfront delete-origin-access-control \
    --id ${ORIGIN_ACCESS_CONTROL_ID} \
    --if-match ${ETAG}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # ETagを取得
[cloudshell-user@ip-10-130-61-60 ~]$ ETAG=$(
>     aws cloudfront get-origin-access-control \
>         --id ${ORIGIN_ACCESS_CONTROL_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
ETVPDKIKX0DER
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ aws cloudfront delete-origin-access-control \
>     --id ${ORIGIN_ACCESS_CONTROL_ID} \
>     --if-match ${ETAG}
```
## Route53
### Hosted Zone内のレコードセットを取得
```bash:コマンド
# レコードセットリストの取得
RECORDSETS_JSON=$(
    aws route53 list-resource-record-sets \
        --hosted-zone-id ${HOSTED_ZONE_ID}
) \
&& echo ${RECORDSETS_JSON}

# JSONフォーマットの確認
echo ${RECORDSETS_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # レコードセットリストの取得
[cloudshell-user@ip-10-130-61-60 ~]$ RECORDSETS_JSON=$(
>     aws route53 list-resource-record-sets \
>         --hosted-zone-id ${HOSTED_ZONE_ID}
> ) \
> && echo ${RECORDSETS_JSON}
{ "ResourceRecordSets": [ { "Name": "handson.example.com.", "Type": "A", "AliasTarget": { "HostedZoneId": "Z2FDTNDATAQYW2", "DNSName": "d2xpr76fxshx5q.cloudfront.net.", "EvaluateTargetHealth": true } }, { "Name": "handson.example.com.", "Type": "NS", "TTL": 172800, "ResourceRecords": [ { "Value": "ns-1260.awsdns-29.org." }, { "Value": "ns-902.awsdns-48.net." }, { "Value": "ns-1560.awsdns-03.co.uk." }, { "Value": "ns-461.awsdns-57.com." } ] }, { "Name": "handson.example.com.", "Type": "SOA", "TTL": 900, "ResourceRecords": [ { "Value": "ns-1260.awsdns-29.org. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" } ] }, { "Name": "_e049795f32552612c6135c8d935dd7e5.handson.example.com.", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws." } ] } ] }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${RECORDSETS_JSON} | python -m json.tool
{
    "ResourceRecordSets": [
        {
            "Name": "handson.example.com.",
            "Type": "A",
            "AliasTarget": {
                "HostedZoneId": "Z2FDTNDATAQYW2",
                "DNSName": "d2xpr76fxshx5q.cloudfront.net.",
                "EvaluateTargetHealth": true
            }
        },
        {
            "Name": "handson.example.com.",
            "Type": "NS",
            "TTL": 172800,
            "ResourceRecords": [
                {
                    "Value": "ns-1260.awsdns-29.org."
                },
                {
                    "Value": "ns-902.awsdns-48.net."
                },
                {
                    "Value": "ns-1560.awsdns-03.co.uk."
                },
                {
                    "Value": "ns-461.awsdns-57.com."
                }
            ]
        },
        {
            "Name": "handson.example.com.",
            "Type": "SOA",
            "TTL": 900,
            "ResourceRecords": [
                {
                    "Value": "ns-1260.awsdns-29.org. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
                }
            ]
        },
        {
            "Name": "_e049795f32552612c6135c8d935dd7e5.handson.example.com.",
            "Type": "CNAME",
            "TTL": 300,
            "ResourceRecords": [
                {
                    "Value": "_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws."
                }
            ]
        }
    ]
}
```
### レコード削除用JSON
```bash:コマンド
DELETE_RECORD_JSON=$(cat << EOF
{
    "Comment": "Deleting a record set",
    "Changes": [
        {
            "Action": "DELETE",
            "ResourceRecordSet": {
                "Name": "handson.example.com.",
                "Type": "A",
                "AliasTarget": {
                    "HostedZoneId": "Z2FDTNDATAQYW2",
                    "DNSName": "d2xpr76fxshx5q.cloudfront.net.",
                    "EvaluateTargetHealth": true
                }
            }
        },
        {
            "Action": "DELETE",
            "ResourceRecordSet": {
                "Name": "_e049795f32552612c6135c8d935dd7e5.handson.example.com.",
                "Type": "CNAME",
                "TTL": 300,
                "ResourceRecords": [
                    {
                        "Value": "_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws."
                    }
                ]
            }
        }
    ]
}
EOF
) \
&& echo ${DELETE_RECORD_JSON}

# JSONフォーマットの確認
echo ${DELETE_RECORD_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ DELETE_RECORD_JSON=$(cat << EOF
> {
>     "Comment": "Deleting a record set",
>     "Changes": [
>         {
>             "Action": "DELETE",
>             "ResourceRecordSet": {
>                 "Name": "handson.example.com.",
>                 "Type": "A",
>                 "AliasTarget": {
>                     "HostedZoneId": "Z2FDTNDATAQYW2",
>                     "DNSName": "d2xpr76fxshx5q.cloudfront.net.",
>                     "EvaluateTargetHealth": true
>                 }
>             }
>         },
>         {
>             "Action": "DELETE",
>             "ResourceRecordSet": {
>                 "Name": "_e049795f32552612c6135c8d935dd7e5.handson.example.com.",
>                 "Type": "CNAME",
>                 "TTL": 300,
>                 "ResourceRecords": [
>                     {
>                         "Value": "_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws."
>                     }
>                 ]
>             }
>         }
>     ]
> }
> EOF
> ) \
> && echo ${DELETE_RECORD_JSON}
{ "Comment": "Deleting a record set", "Changes": [ { "Action": "DELETE", "ResourceRecordSet": { "Name": "handson.example.com.", "Type": "A", "AliasTarget": { "HostedZoneId": "Z2FDTNDATAQYW2", "DNSName": "d2xpr76fxshx5q.cloudfront.net.", "EvaluateTargetHealth": true } } }, { "Action": "DELETE", "ResourceRecordSet": { "Name": "_e049795f32552612c6135c8d935dd7e5.handson.example.com.", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws." } ] } } ] }
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-130-61-60 ~]$ echo ${DELETE_RECORD_JSON} | python -m json.tool
{
    "Comment": "Deleting a record set",
    "Changes": [
        {
            "Action": "DELETE",
            "ResourceRecordSet": {
                "Name": "handson.example.com.",
                "Type": "A",
                "AliasTarget": {
                    "HostedZoneId": "Z2FDTNDATAQYW2",
                    "DNSName": "d2xpr76fxshx5q.cloudfront.net.",
                    "EvaluateTargetHealth": true
                }
            }
        },
        {
            "Action": "DELETE",
            "ResourceRecordSet": {
                "Name": "_e049795f32552612c6135c8d935dd7e5.handson.example.com.",
                "Type": "CNAME",
                "TTL": 300,
                "ResourceRecords": [
                    {
                        "Value": "_386e01e1ba95af93def7ed60e3413159.sdgjtdhdhz.acm-validations.aws."
                    }
                ]
            }
        }
    ]
}
```
### レコードセットを削除
```bash:コマンド
aws route53 change-resource-record-sets \
    --hosted-zone-id ${HOSTED_ZONE_ID} \
    --change-batch "${DELETE_RECORD_JSON}"
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ aws route53 change-resource-record-sets \
>     --hosted-zone-id ${HOSTED_ZONE_ID} \
>     --change-batch "${DELETE_RECORD_JSON}"
{
    "ChangeInfo": {
        "Id": "/change/C03490542FN7OOWE8GZDW",
        "Status": "PENDING",
        "SubmittedAt": "2024-07-21T12:53:20.504000+00:00",
        "Comment": "Deleting a record set"
    }
}
```
### ホストゾーンを削除
```bash:コマンド
aws route53 delete-hosted-zone \
    --id ${HOSTED_ZONE_ID}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ aws route53 delete-hosted-zone \
>     --id ${HOSTED_ZONE_ID}
{
    "ChangeInfo": {
        "Id": "/change/C03626171CRT9GFIP49U0",
        "Status": "PENDING",
        "SubmittedAt": "2024-07-21T12:54:15.947000+00:00"
    }
}
```
## S3バケット
```bash:コマンド
aws s3 rm s3://${S3_BUCKET_NAME} \
    --recursive

# S3バケットを削除
aws s3api delete-bucket \
    --bucket ${S3_BUCKET_NAME}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ aws s3 rm s3://${S3_BUCKET_NAME} \
>     --recursive
delete: s3://handson.example.com/css/styles.css
delete: s3://handson.example.com/img/lambda.png
delete: s3://handson.example.com/favicon.ico
delete: s3://handson.example.com/index.html
[cloudshell-user@ip-10-130-61-60 ~]$ 
[cloudshell-user@ip-10-130-61-60 ~]$ # S3バケットを削除
[cloudshell-user@ip-10-130-61-60 ~]$ aws s3api delete-bucket \
>     --bucket ${S3_BUCKET_NAME}
```
## Cloud9
```bash:コマンド
aws cloud9 delete-environment \
    --environment-id ${CLOUD9_ENVIRONMENT_ID}
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ aws cloud9 delete-environment \
>     --environment-id ${CLOUD9_ENVIRONMENT_ID}
```
## ACM
```bash:コマンド
# ACM証明書の削除
aws acm delete-certificate \
     --certificate-arn ${CERTIFICATE_ARN} \
     --region us-east-1
```
```bash:出力
[cloudshell-user@ip-10-130-61-60 ~]$ # ACM証明書の削除
[cloudshell-user@ip-10-130-61-60 ~]$ aws acm delete-certificate \
>      --certificate-arn ${CERTIFICATE_ARN} \
>      --region us-east-1
```