「AWS Hands-on for Beginners Amazon CloudFrontおよびAWS WAFを用いて エッジサービスの活用方法を学ぼう」をAWS CLIでやってみる

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

上記、「AWS Hands-on for Beginners Amazon CloudFrontおよびAWS WAFを用いて エッジサービスの活用方法を学ぼう | AWS Webinar」 をAWS CLIでやってみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3297641/ed4eb45e-a35f-26fd-3aeb-c085bad3e529.png)
ハンズオンから引用

# 04 Amazon CloudFrontのハンズオン その1 (静的コンテンツの配信設定)
## S3バケット作成
```bash:コマンド
# 変数設定
DATE_VAR=$(date +%Y%m%d) \
&& echo ${DATE_VAR}

S3_BUCKET_NAME=${DATE_VAR}-handson-sincere-networker \
&& echo ${S3_BUCKET_NAME}

REGION="us-east-1" \
&& echo ${REGION}

# バケット作成
aws s3api create-bucket \
    --bucket ${S3_BUCKET_NAME} \
    --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # 変数設定
[cloudshell-user@ip-10-134-11-244 ~]$ DATE_VAR=$(date +%Y%m%d) \
> && echo ${DATE_VAR}
20240804
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ S3_BUCKET_NAME=${DATE_VAR}-handson-sincere-networker \
> && echo ${S3_BUCKET_NAME}
20240804-handson-sincere-networker
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ REGION="us-east-1" \
> && echo ${REGION}
us-east-1
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # バケット作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws s3api create-bucket \
>     --bucket ${S3_BUCKET_NAME} \
>     --region ${REGION}
{
    "Location": "/20240804-handson-sincere-networker"
}
```
## ファイルのアップロード
```bash:コマンド
aws s3 cp forS3/. s3://${S3_BUCKET_NAME}  --recursive
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ aws s3 cp forS3/. s3://${S3_BUCKET_NAME}  --recursive
upload: forS3/static/js/script.js to s3://20240804-handson-sincere-networker/static/js/script.js
upload: forS3/static/css/styles.css to s3://20240804-handson-sincere-networker/static/css/styles.css
upload: forS3/index.html to s3://20240804-handson-sincere-networker/index.html
upload: forS3/static/image/cloudfront.png to s3://20240804-handson-sincere-networker/static/image/cloudfront.png
```
## CloudFront作成
### ディストリビューション作成
:::note info
条件
<INS>Origin</INS>
- Origin Domain Name : 20240724-handson-sincere-networker.s3.us-east-1.amazonaws.com
- オリジンアクセス ：  Origin access control setting (recommended)

<INS>Behavior</INS>
- Redirect HTTP to HTTPS
- キャッシュポリシー：CachingDisabled

<INS>設定</INS>
デフォルトルートオブジェクト：index.html。
:::
```bash:コマンド
# 変数
ORIGIN_DOMAIN_NAME="${S3_BUCKET_NAME}.s3.us-east-1.amazonaws.com" \
&& echo ${ORIGIN_DOMAIN_NAME}

DEFAULT_ROOT_OBJECT="index.html" \
&& echo ${DEFAULT_ROOT_OBJECT}

# ディストリビューションを作成
aws cloudfront create-distribution \
    --origin-domain-name ${ORIGIN_DOMAIN_NAME} \
    --default-root-object ${DEFAULT_ROOT_OBJECT} \
    --no-cli-pager

# ディストリビューション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}

# オリジンIDを変数に保存
DISTRIBUTION_ORIGIN_ID=$(
    aws cloudfront get-distribution \
        --id ${DISTRIBUTION_ID} \
        --query "Distribution.DistributionConfig.Origins.Items[?DomainName=='${ORIGIN_DOMAIN_NAME}'].Id" \
        --output text
) \
&& echo ${DISTRIBUTION_ORIGIN_ID}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # 変数
[cloudshell-user@ip-10-134-11-244 ~]$ ORIGIN_DOMAIN_NAME="${S3_BUCKET_NAME}.s3.us-east-1.amazonaws.com" \
> && echo ${ORIGIN_DOMAIN_NAME}
20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ DEFAULT_ROOT_OBJECT="index.html" \
> && echo ${DEFAULT_ROOT_OBJECT}
index.html
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ディストリビューションを作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront create-distribution \
>     --origin-domain-name ${ORIGIN_DOMAIN_NAME} \
>     --default-root-object ${DEFAULT_ROOT_OBJECT} \
>     --no-cli-pager
{
    "Location": "https://cloudfront.amazonaws.com/2020-05-31/distribution/EIN33GD07JLDT",
    "ETag": "E34O58LV5JBI3M",
    "Distribution": {
        "Id": "EIN33GD07JLDT",
        "ARN": "arn:aws:cloudfront::999999999999:distribution/EIN33GD07JLDT",
        "Status": "InProgress",
        "LastModifiedTime": "2024-08-04T10:32:35.088000+00:00",
        "InProgressInvalidationBatches": 0,
        "DomainName": "d18sbbratjvl6c.cloudfront.net",
        "ActiveTrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ActiveTrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "DistributionConfig": {
            "CallerReference": "cli-1722767554-44223",
            "Aliases": {
                "Quantity": 0
            },
            "DefaultRootObject": "index.html",
            "Origins": {
                "Quantity": 1,
                "Items": [
                    {
                        "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                        "DomainName": "20240804-handson-sincere-networker.s3.us-east-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": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "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
        }
    }
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ディストリビューションIDを変数に保存
[cloudshell-user@ip-10-134-11-244 ~]$ DISTRIBUTION_ID=$(
>     aws cloudfront list-distributions \
>         --query "DistributionList.Items[?Origins.Items[?DomainName=='${ORIGIN_DOMAIN_NAME}']].Id" \
>         --output text
> ) \
> && echo ${DISTRIBUTION_ID}
EIN33GD07JLDT
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ディストリビューションドメイン名を変数に保存
[cloudshell-user@ip-10-134-11-244 ~]$ DISTRIBUTION_DOMAINNAME=$(
>     aws cloudfront list-distributions \
>         --query "DistributionList.Items[?Origins.Items[?DomainName=='${ORIGIN_DOMAIN_NAME}']].DomainName" \
>         --output text
> ) \
> && echo ${DISTRIBUTION_DOMAINNAME}
d18sbbratjvl6c.cloudfront.net
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ディストリビューションARNを変数に保存
[cloudshell-user@ip-10-134-11-244 ~]$ DISTRIBUTION_ARN=$(
>     aws cloudfront get-distribution \
>         --id ${DISTRIBUTION_ID} \
>         --query "Distribution.ARN" \
>         --output text
> ) \
> && echo ${DISTRIBUTION_ARN}
arn:aws:cloudfront::999999999999:distribution/EIN33GD07JLDT
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # オリジンIDを変数に保存
[cloudshell-user@ip-10-134-11-244 ~]$ DISTRIBUTION_ORIGIN_ID=$(
>     aws cloudfront get-distribution \
>         --id ${DISTRIBUTION_ID} \
>         --query "Distribution.DistributionConfig.Origins.Items[?DomainName=='${ORIGIN_DOMAIN_NAME}'].Id" \
>         --output text
> ) \
> && echo ${DISTRIBUTION_ORIGIN_ID}
20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934
```
### オリジンアクセス作成
```bash:コマンド
# オリジンアクセス用JSON
ORIGIN_ACCESS_JSON=$(cat << EOF
{
    "Name": "${ORIGIN_DOMAIN_NAME}",
    "SigningProtocol": "sigv4",
    "SigningBehavior": "always",
    "OriginAccessControlOriginType": "s3"
}
EOF
) \
&& echo ${ORIGIN_ACCESS_JSON}

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

# 作成
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=='${ORIGIN_DOMAIN_NAME}'].Id" \
        --output text
) \
&& echo ${ORIGIN_ACCESS_CONTROL_ID} 
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # オリジンアクセス用JSON
[cloudshell-user@ip-10-134-11-244 ~]$ ORIGIN_ACCESS_JSON=$(cat << EOF
> {
>     "Name": "${ORIGIN_DOMAIN_NAME}",
>     "SigningProtocol": "sigv4",
>     "SigningBehavior": "always",
>     "OriginAccessControlOriginType": "s3"
> }
> EOF
> ) \
> && echo ${ORIGIN_ACCESS_JSON}
{ "Name": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com", "SigningProtocol": "sigv4", "SigningBehavior": "always", "OriginAccessControlOriginType": "s3" }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${ORIGIN_ACCESS_JSON} | python -m json.tool
{
    "Name": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
    "SigningProtocol": "sigv4",
    "SigningBehavior": "always",
    "OriginAccessControlOriginType": "s3"
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # 作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront create-origin-access-control \
>     --origin-access-control-config "${ORIGIN_ACCESS_JSON}"
{
    "Location": "https://cloudfront.amazonaws.com/2020-05-31/origin-access-control/E2G9MJEEXTOJC1",
    "ETag": "ETVPDKIKX0DER",
    "OriginAccessControl": {
        "Id": "E2G9MJEEXTOJC1",
        "OriginAccessControlConfig": {
            "Name": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
            "SigningProtocol": "sigv4",
            "SigningBehavior": "always",
            "OriginAccessControlOriginType": "s3"
        }
    }
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ID取得
[cloudshell-user@ip-10-134-11-244 ~]$ ORIGIN_ACCESS_CONTROL_ID=$(
>     aws cloudfront list-origin-access-controls \
>         --query "OriginAccessControlList.Items[?Name=='${ORIGIN_DOMAIN_NAME}'].Id" \
>         --output text
> ) \
> && echo ${ORIGIN_ACCESS_CONTROL_ID} 
E2G9MJEEXTOJC1
```
### ディストリビューション デフォルト設定バックアップ
```bash:コマンド
# デフォルト設定JSON
CONFIG_BEFORE=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        --query "DistributionConfig"
) \
&& echo ${CONFIG_BEFORE}

# JSONフォーマットの確認
echo ${CONFIG_BEFORE} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # デフォルト設定JSON
[cloudshell-user@ip-10-134-11-244 ~]$ CONFIG_BEFORE=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query "DistributionConfig"
> ) \
> && echo ${CONFIG_BEFORE}
{ "CallerReference": "cli-1722767554-44223", "Aliases": { "Quantity": 0 }, "DefaultRootObject": "index.html", "Origins": { "Quantity": 1, "Items": [ { "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "DomainName": "20240804-handson-sincere-networker.s3.us-east-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": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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 }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${CONFIG_BEFORE} | python -m json.tool
{
    "CallerReference": "cli-1722767554-44223",
    "Aliases": {
        "Quantity": 0
    },
    "DefaultRootObject": "index.html",
    "Origins": {
        "Quantity": 1,
        "Items": [
            {
                "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "DomainName": "20240804-handson-sincere-networker.s3.us-east-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": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
        "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
}
```
### キャッシュポリシー(Managed-CachingDisabled) ID取得
```bash:コマンド
# キャッシュポリシー名
CACHE_POLICYCONFIG_NAME="Managed-CachingDisabled" \
&& echo ${CACHEPOLICYCONFIG_NAME}

# キャッシュポリシー名を指定してId取得
MANAGED_CACHING_DISABLED_ID=$(
    aws cloudfront list-cache-policies \
        --query "CachePolicyList.Items[?CachePolicy.CachePolicyConfig.Name=='${CACHE_POLICYCONFIG_NAME}'].CachePolicy.Id" \
        --output text
) \
&& echo ${MANAGED_CACHING_DISABLED_ID}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # キャッシュポリシー名
[cloudshell-user@ip-10-134-11-244 ~]$ CACHE_POLICYCONFIG_NAME="Managed-CachingDisabled" \
> && echo ${CACHEPOLICYCONFIG_NAME}

[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # キャッシュポリシー名を指定してId取得
[cloudshell-user@ip-10-134-11-244 ~]$ MANAGED_CACHING_DISABLED_ID=$(
>     aws cloudfront list-cache-policies \
>         --query "CachePolicyList.Items[?CachePolicy.CachePolicyConfig.Name=='${CACHE_POLICYCONFIG_NAME}'].CachePolicy.Id" \
>         --output text
> ) \
> && echo ${MANAGED_CACHING_DISABLED_ID}
4135ea2d-6df8-44a3-9df3-4b5a84be39ad
```
### ディストリビューション変更用JSON
```bash:コマンド
# ディストリビューション変更用JSON
CONFIG=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        --query "DistributionConfig" \
        | jq 'del(.DefaultCacheBehavior.ForwardedValues)' \
        | jq 'del(.DefaultCacheBehavior.MinTTL)' \
        | jq 'del(.DefaultCacheBehavior.DefaultTTL)' \
        | jq 'del(.DefaultCacheBehavior.MaxTTL)' \
        | jq '.DefaultCacheBehavior.ViewerProtocolPolicy = "redirect-to-https"' \
        | jq '.DefaultCacheBehavior.Compress = true' \
        | jq --arg cachepolicyId "${MANAGED_CACHING_DISABLED_ID}" '.DefaultCacheBehavior.CachePolicyId = $cachepolicyId' \
        | jq 'del(.Origins.Items[].CustomOriginConfig)' \
        | jq '.Origins.Items[].S3OriginConfig = {"OriginAccessIdentity": ""}' \
        | jq --arg originId "${ORIGIN_ACCESS_CONTROL_ID}" '.Origins.Items.[].OriginAccessControlId = $originId'
) \
&& echo ${CONFIG}

# JSONフォーマットの確認
echo ${CONFIG} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ディストリビューション変更用JSON
[cloudshell-user@ip-10-134-11-244 ~]$ CONFIG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query "DistributionConfig" \
>         | jq 'del(.DefaultCacheBehavior.ForwardedValues)' \
>         | jq 'del(.DefaultCacheBehavior.MinTTL)' \
>         | jq 'del(.DefaultCacheBehavior.DefaultTTL)' \
>         | jq 'del(.DefaultCacheBehavior.MaxTTL)' \
>         | jq '.DefaultCacheBehavior.ViewerProtocolPolicy = "redirect-to-https"' \
>         | jq '.DefaultCacheBehavior.Compress = true' \
>         | jq --arg cachepolicyId "${MANAGED_CACHING_DISABLED_ID}" '.DefaultCacheBehavior.CachePolicyId = $cachepolicyId' \
>         | jq 'del(.Origins.Items[].CustomOriginConfig)' \
>         | jq '.Origins.Items[].S3OriginConfig = {"OriginAccessIdentity": ""}' \
>         | jq --arg originId "${ORIGIN_ACCESS_CONTROL_ID}" '.Origins.Items.[].OriginAccessControlId = $originId'
> ) \
> && echo ${CONFIG}
{ "CallerReference": "cli-1722767554-44223", "Aliases": { "Quantity": 0 }, "DefaultRootObject": "index.html", "Origins": { "Quantity": 1, "Items": [ { "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "E2G9MJEEXTOJC1", "S3OriginConfig": { "OriginAccessIdentity": "" } } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" }, "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 }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${CONFIG} | python -m json.tool
{
    "CallerReference": "cli-1722767554-44223",
    "Aliases": {
        "Quantity": 0
    },
    "DefaultRootObject": "index.html",
    "Origins": {
        "Quantity": 1,
        "Items": [
            {
                "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": "E2G9MJEEXTOJC1",
                "S3OriginConfig": {
                    "OriginAccessIdentity": ""
                }
            }
        ]
    },
    "OriginGroups": {
        "Quantity": 0
    },
    "DefaultCacheBehavior": {
        "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
        "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": true,
        "LambdaFunctionAssociations": {
            "Quantity": 0
        },
        "FunctionAssociations": {
            "Quantity": 0
        },
        "FieldLevelEncryptionId": "",
        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
    },
    "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:コマンド
# 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}" \
    --if-match ${ETAG} \
    --no-cli-pager
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ETagを取得
[cloudshell-user@ip-10-134-11-244 ~]$ ETAG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
E34O58LV5JBI3M
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # CloudFrontディストリビューションの設定を更新
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront update-distribution \
>     --id ${DISTRIBUTION_ID} \
>     --distribution-config "${CONFIG}" \
>     --if-match ${ETAG} \
>     --no-cli-pager
{
    "ETag": "EYFF12T0DBGKW",
    "Distribution": {
        "Id": "EIN33GD07JLDT",
        "ARN": "arn:aws:cloudfront::999999999999:distribution/EIN33GD07JLDT",
        "Status": "InProgress",
        "LastModifiedTime": "2024-08-04T10:40:04.403000+00:00",
        "InProgressInvalidationBatches": 0,
        "DomainName": "d18sbbratjvl6c.cloudfront.net",
        "ActiveTrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ActiveTrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "DistributionConfig": {
            "CallerReference": "cli-1722767554-44223",
            "Aliases": {
                "Quantity": 0
            },
            "DefaultRootObject": "index.html",
            "Origins": {
                "Quantity": 1,
                "Items": [
                    {
                        "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                        "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "S3OriginConfig": {
                            "OriginAccessIdentity": ""
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": "E2G9MJEEXTOJC1"
                    }
                ]
            },
            "OriginGroups": {
                "Quantity": 0
            },
            "DefaultCacheBehavior": {
                "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
            },
            "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
        }
    }
}
```
## S3変更
### バケットポリシー追加
```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

# バケットポリシー
aws s3api put-bucket-policy \
    --bucket ${S3_BUCKET_NAME} \
    --policy "${BACKET_POLICY}"
    
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # バケットポリシー(JSON)
[cloudshell-user@ip-10-134-11-244 ~]$ 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:::20240804-handson-sincere-networker/*", "Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::999999999999:distribution/EIN33GD07JLDT" } } } ] }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ 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:::20240804-handson-sincere-networker/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::999999999999:distribution/EIN33GD07JLDT"
                }
            }
        }
    ]
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # バケットポリシー
[cloudshell-user@ip-10-134-11-244 ~]$ aws s3api put-bucket-policy \
>     --bucket ${S3_BUCKET_NAME} \
>     --policy "${BACKET_POLICY}"
```
## アクセス確認
```bash:コマンド
curl https://${DISTRIBUTION_DOMAINNAME}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ curl https://${DISTRIBUTION_DOMAINNAME}
<!DOCTYPE html>
<html>
  <head>
    <link rel="icon" type="image/x-icon" href="static/image/cloudfront.png">
    <link href="static/css/styles.css" rel="stylesheet" type="text/css">
    <script src="static/js/script.js"></script>
  </head>
  <body>
    <form id="form1" action="#">
        <ul>
            <li>
              <img src="static/image/cloudfront.png" width="100" height="100">
            </li>
            <li>
              <p>Input Message</p>
              <textarea id="input_message" rows="4" cols="40"></textarea>
            </li>
            <li>
                <input type="button" onclick="func1()" value="Send" />
                <input type="button" onclick="func2()" value="All Clear"  />
            </li>
            <li>
                <br />
                <p>Output Message</p>
                <textarea id="output_message" rows="4" cols="40"></textarea>
            </li>
          </ul>
    </form>
  </body>
</html>
```
# 05 Amazon CloudFrontのハンズオン その2 (コンテンツキャッシュの設定)
## キャッシュポリシー作成
### 設定JSON
```bash:コマンド
# キャッシュポリシー名
CACHEPOLICY_NAME="handson-cachepolicy" \
&& echo ${CACHEPOLICY_NAME}

# キャッシュポリシー設定JSON
CACHEPOLICY_JSON=$(cat << EOF
{
    "Comment": "",
    "Name": "handson-cachepolicy",
    "DefaultTTL": 86400,
    "MaxTTL": 31536000,
    "MinTTL": 1,
    "ParametersInCacheKeyAndForwardedToOrigin": {
        "EnableAcceptEncodingGzip": true,
        "EnableAcceptEncodingBrotli": true,
        "HeadersConfig": {
            "HeaderBehavior": "none"
        },
        "CookiesConfig": {
            "CookieBehavior": "none"
        },
        "QueryStringsConfig": {
            "QueryStringBehavior": "none"
        }
    }
}
EOF
) \
&& echo ${CACHEPOLICY_JSON}

# JSONフォーマットの確認
echo ${CACHEPOLICY_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # キャッシュポリシー名
[cloudshell-user@ip-10-134-11-244 ~]$ CACHEPOLICY_NAME="handson-cachepolicy" \
> && echo ${CACHEPOLICY_NAME}
handson-cachepolicy
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # キャッシュポリシー設定JSON
[cloudshell-user@ip-10-134-11-244 ~]$ CACHEPOLICY_JSON=$(cat << EOF
> {
>     "Comment": "",
>     "Name": "handson-cachepolicy",
>     "DefaultTTL": 86400,
>     "MaxTTL": 31536000,
>     "MinTTL": 1,
>     "ParametersInCacheKeyAndForwardedToOrigin": {
>         "EnableAcceptEncodingGzip": true,
>         "EnableAcceptEncodingBrotli": true,
>         "HeadersConfig": {
>             "HeaderBehavior": "none"
>         },
>         "CookiesConfig": {
>             "CookieBehavior": "none"
>         },
>         "QueryStringsConfig": {
>             "QueryStringBehavior": "none"
>         }
>     }
> }
> EOF
> ) \
> && echo ${CACHEPOLICY_JSON}
{ "Comment": "", "Name": "handson-cachepolicy", "DefaultTTL": 86400, "MaxTTL": 31536000, "MinTTL": 1, "ParametersInCacheKeyAndForwardedToOrigin": { "EnableAcceptEncodingGzip": true, "EnableAcceptEncodingBrotli": true, "HeadersConfig": { "HeaderBehavior": "none" }, "CookiesConfig": { "CookieBehavior": "none" }, "QueryStringsConfig": { "QueryStringBehavior": "none" } } }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${CACHEPOLICY_JSON} | python -m json.tool
{
    "Comment": "",
    "Name": "handson-cachepolicy",
    "DefaultTTL": 86400,
    "MaxTTL": 31536000,
    "MinTTL": 1,
    "ParametersInCacheKeyAndForwardedToOrigin": {
        "EnableAcceptEncodingGzip": true,
        "EnableAcceptEncodingBrotli": true,
        "HeadersConfig": {
            "HeaderBehavior": "none"
        },
        "CookiesConfig": {
            "CookieBehavior": "none"
        },
        "QueryStringsConfig": {
            "QueryStringBehavior": "none"
        }
    }
}
```
### キャッシュポリシー設定
```bash:コマンド
# キャッシュポリシー作成
aws cloudfront create-cache-policy \
    --cache-policy-config "${CACHEPOLICY_JSON}"

# キャッシュポリシー名を指定してId取得
CACHEPOLICY_ID=$(
    aws cloudfront list-cache-policies \
        --query "CachePolicyList.Items[?CachePolicy.CachePolicyConfig.Name=='${CACHEPOLICY_NAME}'].CachePolicy.Id" \
        --output text
) \
&& echo ${CACHEPOLICY_ID}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # キャッシュポリシー作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront create-cache-policy \
>     --cache-policy-config "${CACHEPOLICY_JSON}"
{
    "Location": "https://cloudfront.amazonaws.com/2020-05-31/cache-policy/fe0144f2-7815-4b78-9544-cc88b1e0fedf",
    "ETag": "E23ZP02F085DFQ",
    "CachePolicy": {
        "Id": "fe0144f2-7815-4b78-9544-cc88b1e0fedf",
        "LastModifiedTime": "2024-08-04T10:44:08.178000+00:00",
        "CachePolicyConfig": {
            "Comment": "",
            "Name": "handson-cachepolicy",
            "DefaultTTL": 86400,
            "MaxTTL": 31536000,
            "MinTTL": 1,
            "ParametersInCacheKeyAndForwardedToOrigin": {
                "EnableAcceptEncodingGzip": true,
                "EnableAcceptEncodingBrotli": true,
                "HeadersConfig": {
                    "HeaderBehavior": "none"
                },
                "CookiesConfig": {
                    "CookieBehavior": "none"
                },
                "QueryStringsConfig": {
                    "QueryStringBehavior": "none"
                }
            }
        }
    }
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # キャッシュポリシー名を指定してId取得
[cloudshell-user@ip-10-134-11-244 ~]$ CACHEPOLICY_ID=$(
>     aws cloudfront list-cache-policies \
>         --query "CachePolicyList.Items[?CachePolicy.CachePolicyConfig.Name=='${CACHEPOLICY_NAME}'].CachePolicy.Id" \
>         --output text
> ) \
> && echo ${CACHEPOLICY_ID}
fe0144f2-7815-4b78-9544-cc88b1e0fedf
```
## ビヘイビア追加
:::note info
条件
- パスパターン：/static/*
- Redirect HTTP to HTTPS
- キャッシュポリシー：CachingDisabled
:::
### ビヘイビアJSON
```bash:コマンド
# ビヘイビア設定JSON
BEHAVIOR_JSON=$(cat << EOF
{
    "Quantity": 1,
    "Items": [
        {
            "PathPattern": "/static/*",
            "TargetOriginId": "${DISTRIBUTION_ORIGIN_ID}",
            "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": true,
            "LambdaFunctionAssociations": {
                "Quantity": 0
            },
            "FunctionAssociations": {
                "Quantity": 0
            },
            "FieldLevelEncryptionId": "",
            "CachePolicyId": "${CACHEPOLICY_ID}"
        }
    ]
}
EOF
) \
&& echo ${BEHAVIOR_JSON}

# JSONフォーマットの確認
echo ${BEHAVIOR_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ビヘイビア設定JSON
[cloudshell-user@ip-10-134-11-244 ~]$ BEHAVIOR_JSON=$(cat << EOF
> {
>     "Quantity": 1,
>     "Items": [
>         {
>             "PathPattern": "/static/*",
>             "TargetOriginId": "${DISTRIBUTION_ORIGIN_ID}",
>             "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": true,
>             "LambdaFunctionAssociations": {
>                 "Quantity": 0
>             },
>             "FunctionAssociations": {
>                 "Quantity": 0
>             },
>             "FieldLevelEncryptionId": "",
>             "CachePolicyId": "${CACHEPOLICY_ID}"
>         }
>     ]
> }
> EOF
> ) \
> && echo ${BEHAVIOR_JSON}
{ "Quantity": 1, "Items": [ { "PathPattern": "/static/*", "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf" } ] }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${BEHAVIOR_JSON} | python -m json.tool
{
    "Quantity": 1,
    "Items": [
        {
            "PathPattern": "/static/*",
            "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
            "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": true,
            "LambdaFunctionAssociations": {
                "Quantity": 0
            },
            "FunctionAssociations": {
                "Quantity": 0
            },
            "FieldLevelEncryptionId": "",
            "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf"
        }
    ]
}
```
## ディストリビューションJSON (ビヘイビア追加)
### ディストリビューションJSON 
```bash:コマンド
# ディストリビューション変更用JSON
CONFIG=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        --query "DistributionConfig" \
        | jq --argjson behavior "${BEHAVIOR_JSON}" '.CacheBehaviors = $behavior'
) \
&& echo ${CONFIG}

# JSONフォーマットの確認
echo ${CONFIG} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ディストリビューション変更用JSON
[cloudshell-user@ip-10-134-11-244 ~]$ CONFIG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query "DistributionConfig" \
>         | jq --argjson behavior "${BEHAVIOR_JSON}" '.CacheBehaviors = $behavior'
> ) \
> && echo ${CONFIG}
{ "CallerReference": "cli-1722767554-44223", "Aliases": { "Quantity": 0 }, "DefaultRootObject": "index.html", "Origins": { "Quantity": 1, "Items": [ { "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "S3OriginConfig": { "OriginAccessIdentity": "" }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "E2G9MJEEXTOJC1" } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" }, "CacheBehaviors": { "Quantity": 1, "Items": [ { "PathPattern": "/static/*", "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf" } ] }, "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 }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${CONFIG} | python -m json.tool
{
    "CallerReference": "cli-1722767554-44223",
    "Aliases": {
        "Quantity": 0
    },
    "DefaultRootObject": "index.html",
    "Origins": {
        "Quantity": 1,
        "Items": [
            {
                "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "S3OriginConfig": {
                    "OriginAccessIdentity": ""
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": "E2G9MJEEXTOJC1"
            }
        ]
    },
    "OriginGroups": {
        "Quantity": 0
    },
    "DefaultCacheBehavior": {
        "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
        "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": true,
        "LambdaFunctionAssociations": {
            "Quantity": 0
        },
        "FunctionAssociations": {
            "Quantity": 0
        },
        "FieldLevelEncryptionId": "",
        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
    },
    "CacheBehaviors": {
        "Quantity": 1,
        "Items": [
            {
                "PathPattern": "/static/*",
                "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf"
            }
        ]
    },
    "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:コマンド
# 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}" \
    --if-match ${ETAG} \
    --no-cli-pager
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # CloudFrontディストリビューションの設定を更新
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront update-distribution \
>     --id ${DISTRIBUTION_ID} \
>     --distribution-config "${CONFIG}" \
>     --if-match ${ETAG} \
>     --no-cli-pager
{
    "ETag": "E3H7EIKSZ5KXEF",
    "Distribution": {
        "Id": "EIN33GD07JLDT",
        "ARN": "arn:aws:cloudfront::999999999999:distribution/EIN33GD07JLDT",
        "Status": "InProgress",
        "LastModifiedTime": "2024-08-04T10:45:59.549000+00:00",
        "InProgressInvalidationBatches": 0,
        "DomainName": "d18sbbratjvl6c.cloudfront.net",
        "ActiveTrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ActiveTrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "DistributionConfig": {
            "CallerReference": "cli-1722767554-44223",
            "Aliases": {
                "Quantity": 0
            },
            "DefaultRootObject": "index.html",
            "Origins": {
                "Quantity": 1,
                "Items": [
                    {
                        "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                        "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "S3OriginConfig": {
                            "OriginAccessIdentity": ""
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": "E2G9MJEEXTOJC1"
                    }
                ]
            },
            "OriginGroups": {
                "Quantity": 0
            },
            "DefaultCacheBehavior": {
                "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
            },
            "CacheBehaviors": {
                "Quantity": 1,
                "Items": [
                    {
                        "PathPattern": "/static/*",
                        "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                        "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": true,
                        "LambdaFunctionAssociations": {
                            "Quantity": 0
                        },
                        "FunctionAssociations": {
                            "Quantity": 0
                        },
                        "FieldLevelEncryptionId": "",
                        "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf"
                    }
                ]
            },
            "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:コマンド
curl https://${DISTRIBUTION_DOMAINNAME}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ curl https://${DISTRIBUTION_DOMAINNAME}
<!DOCTYPE html>
<html>
  <head>
    <link rel="icon" type="image/x-icon" href="static/image/cloudfront.png">
    <link href="static/css/styles.css" rel="stylesheet" type="text/css">
    <script src="static/js/script.js"></script>
  </head>
  <body>
    <form id="form1" action="#">
        <ul>
            <li>
              <img src="static/image/cloudfront.png" width="100" height="100">
            </li>
            <li>
              <p>Input Message</p>
              <textarea id="input_message" rows="4" cols="40"></textarea>
            </li>
            <li>
                <input type="button" onclick="func1()" value="Send" />
                <input type="button" onclick="func2()" value="All Clear"  />
            </li>
            <li>
                <br />
                <p>Output Message</p>
                <textarea id="output_message" rows="4" cols="40"></textarea>
            </li>
          </ul>
    </form>
  </body>
</html>
```
# 06 Amazon CloudFrontのハンズオン その3 (動的コンテンツの配信設定①)
## Lambda関数作成
:::note info
条件
関数名：handson-lambda
ランタイム：Python 3.8
:::
### 変数設定
```bash:コマンド
# 変数設定
FUNCTION_NAME="handson-lambda" \
&& echo ${FUNCTION_NAME}

RUNTIME="python3.8" \
&& echo ${RUNTIME}

POLICY_NAME="${FUNCTION_NAME}-policy" \
&& echo ${POLICY_NAME}

ROLE_NAME="${FUNCTION_NAME}-role" \
&& echo ${ROLE_NAME}

ATTACH_POLICY_NAME="TranslateReadOnly" \
&& echo ${ATTACH_POLICY_NAME}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # 変数設定
[cloudshell-user@ip-10-134-11-244 ~]$ FUNCTION_NAME="handson-lambda" \
> && echo ${FUNCTION_NAME}
handson-lambda
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ RUNTIME="python3.8" \
> && echo ${RUNTIME}
python3.8
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ POLICY_NAME="${FUNCTION_NAME}-policy" \
> && echo ${POLICY_NAME}
handson-lambda-policy
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ ROLE_NAME="${FUNCTION_NAME}-role" \
> && echo ${ROLE_NAME}
handson-lambda-role
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ ATTACH_POLICY_NAME="TranslateReadOnly" \
> && echo ${ATTACH_POLICY_NAME}
TranslateReadOnly
```
### IAMポリシー作成
```bash:コマンド
# ポリシードキュメントの作成
POLICY_DOCUMENT_JSON=$(cat << EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:${REGION}:999999999999:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:${REGION}:999999999999:log-group:/aws/lambda/${FUNCTION_NAME}:*"
            ]
        }
    ]
}
EOF
) \
&& echo ${POLICY_DOCUMENT_JSON}

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

# ポリシーの作成
aws iam create-policy \
    --policy-name ${POLICY_NAME} \
    --policy-document "${POLICY_DOCUMENT_JSON}"

# ARN取得
POLICY_ARN=$(
    aws iam list-policies \
        --query "Policies[?PolicyName=='${POLICY_NAME}'].Arn" \
        --output text
) \
&& echo ${POLICY_ARN}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ポリシードキュメントの作成
[cloudshell-user@ip-10-134-11-244 ~]$ POLICY_DOCUMENT_JSON=$(cat << EOF
> {
>     "Version": "2012-10-17",
>     "Statement": [
>         {
>             "Effect": "Allow",
>             "Action": "logs:CreateLogGroup",
>             "Resource": "arn:aws:logs:${REGION}:999999999999:*"
>         },
>         {
>             "Effect": "Allow",
>             "Action": [
>                 "logs:CreateLogStream",
>                 "logs:PutLogEvents"
>             ],
>             "Resource": [
>                 "arn:aws:logs:${REGION}:999999999999:log-group:/aws/lambda/${FUNCTION_NAME}:*"
>             ]
>         }
>     ]
> }
> EOF
> ) \
> && echo ${POLICY_DOCUMENT_JSON}
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "arn:aws:logs:us-east-1:999999999999:*" }, { "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:us-east-1:999999999999:log-group:/aws/lambda/handson-lambda:*" ] } ] }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${POLICY_DOCUMENT_JSON} | python -m json.tool
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:us-east-1:999999999999:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:999999999999:log-group:/aws/lambda/handson-lambda:*"
            ]
        }
    ]
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ポリシーの作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws iam create-policy \
>     --policy-name ${POLICY_NAME} \
>     --policy-document "${POLICY_DOCUMENT_JSON}"
{
    "Policy": {
        "PolicyName": "handson-lambda-policy",
        "PolicyId": "ANPAWFKRCMKO4GTU36ISU",
        "Arn": "arn:aws:iam::999999999999:policy/handson-lambda-policy",
        "Path": "/",
        "DefaultVersionId": "v1",
        "AttachmentCount": 0,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true,
        "CreateDate": "2024-08-04T10:49:10+00:00",
        "UpdateDate": "2024-08-04T10:49:10+00:00"
    }
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ARN取得
[cloudshell-user@ip-10-134-11-244 ~]$ POLICY_ARN=$(
>     aws iam list-policies \
>         --query "Policies[?PolicyName=='${POLICY_NAME}'].Arn" \
>         --output text
> ) \
> && echo ${POLICY_ARN}
arn:aws:iam::999999999999:policy/handson-lambda-policy
```
### IAMロール作成
```bash:コマンド
# 信頼関係ポリシードキュメントの作成
ASSUME_ROLE_POLICY_DOCUMENT=$(cat << EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOF
) \
&& echo ${ASSUME_ROLE_POLICY_DOCUMENT}

# IAMロールの作成
aws iam create-role \
    --role-name ${ROLE_NAME} \
    --assume-role-policy-document "${ASSUME_ROLE_POLICY_DOCUMENT}"

# IAMロールにポリシーをアタッチ
aws iam attach-role-policy \
  --role-name ${ROLE_NAME} \
  --policy-arn ${POLICY_ARN}

aws iam attach-role-policy \
  --role-name ${ROLE_NAME} \
  --policy-arn arn:aws:iam::aws:policy/${ATTACH_POLICY_NAME}

# ARN取得
ROLE_ARN=$(
    aws iam get-role \
        --role-name ${ROLE_NAME} \
        --query 'Role.Arn' --output text
) \
&& echo ${ROLE_ARN}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # 信頼関係ポリシードキュメントの作成
[cloudshell-user@ip-10-134-11-244 ~]$ ASSUME_ROLE_POLICY_DOCUMENT=$(cat << EOF
> {
>     "Version": "2012-10-17",
>     "Statement": [
>         {
>             "Effect": "Allow",
>             "Principal": {
>                 "Service": "lambda.amazonaws.com"
>             },
>             "Action": "sts:AssumeRole"
>         }
>     ]
> }
> EOF
> ) \
> && echo ${ASSUME_ROLE_POLICY_DOCUMENT}
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # IAMロールの作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws iam create-role \
>     --role-name ${ROLE_NAME} \
>     --assume-role-policy-document "${ASSUME_ROLE_POLICY_DOCUMENT}"
{
    "Role": {
        "Path": "/",
        "RoleName": "handson-lambda-role",
        "RoleId": "AROAWFKRCMKOZTTQSCLKD",
        "Arn": "arn:aws:iam::999999999999:role/handson-lambda-role",
        "CreateDate": "2024-08-04T10:49:56+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "lambda.amazonaws.com"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        }
    }
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # IAMロールにポリシーをアタッチ
[cloudshell-user@ip-10-134-11-244 ~]$ aws iam attach-role-policy \
>   --role-name ${ROLE_NAME} \
>   --policy-arn ${POLICY_ARN}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ aws iam attach-role-policy \
>   --role-name ${ROLE_NAME} \
>   --policy-arn arn:aws:iam::aws:policy/${ATTACH_POLICY_NAME}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ARN取得
[cloudshell-user@ip-10-134-11-244 ~]$ ROLE_ARN=$(
>     aws iam get-role \
>         --role-name ${ROLE_NAME} \
>         --query 'Role.Arn' --output text
> ) \
> && echo ${ROLE_ARN}
arn:aws:iam::999999999999:role/handson-lambda-role
```
### コードソースの作成
```bash:コマンド
# コードソースの作成
cat << EOF > lambda_function.py
import boto3

def lambda_handler(event, context):
    translate = boto3.client(service_name='translate', use_ssl=True)
    result = translate.translate_text(Text=event['queryStringParameters']['input_text'], SourceLanguageCode="ja", TargetLanguageCode="en").get('TranslatedText')
    return {
        'statusCode': 200,
        'body': result
    }
EOF

cat lambda_function.py
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # コードソースの作成
[cloudshell-user@ip-10-134-11-244 ~]$ cat << EOF > lambda_function.py
> import boto3
> 
> def lambda_handler(event, context):
>     translate = boto3.client(service_name='translate', use_ssl=True)
>     result = translate.translate_text(Text=event['queryStringParameters']['input_text'], SourceLanguageCode="ja", TargetLanguageCode="en").get('TranslatedText')
>     return {
>         'statusCode': 200,
>         'body': result
>     }
> EOF
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ cat lambda_function.py
import boto3

def lambda_handler(event, context):
    translate = boto3.client(service_name='translate', use_ssl=True)
    result = translate.translate_text(Text=event['queryStringParameters']['input_text'], SourceLanguageCode="ja", TargetLanguageCode="en").get('TranslatedText')
    return {
        'statusCode': 200,
        'body': result
    }
```
### デプロイパッケージの作成
```bash:コマンド
# デプロイパッケージの作成
zip function.zip lambda_function.py
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # デプロイパッケージの作成
[cloudshell-user@ip-10-134-11-244 ~]$ zip function.zip lambda_function.py
  adding: lambda_function.py (deflated 35%)
```
### Lambda関数の作成
```bash:コマンド
# Lambda関数の作成
aws lambda create-function \
    --function-name ${FUNCTION_NAME} \
    --runtime ${RUNTIME} \
    --role $ROLE_ARN \
    --handler lambda_function.lambda_handler \
    --zip-file fileb://function.zip \
    --region ${REGION}

# ARNの取得
FUNCTION_ARN=$(
    aws lambda list-functions \
        --query "Functions[?FunctionName=='${FUNCTION_NAME}'].FunctionArn" \
        --output text \
        --region ${REGION}
) \
&& echo ${FUNCTION_ARN}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # Lambda関数の作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws lambda create-function \
>     --function-name ${FUNCTION_NAME} \
>     --runtime ${RUNTIME} \
>     --role $ROLE_ARN \
>     --handler lambda_function.lambda_handler \
>     --zip-file fileb://function.zip \
>     --region ${REGION}
{
    "FunctionName": "handson-lambda",
    "FunctionArn": "arn:aws:lambda:us-east-1:999999999999:function:handson-lambda",
    "Runtime": "python3.8",
    "Role": "arn:aws:iam::999999999999:role/handson-lambda-role",
    "Handler": "lambda_function.lambda_handler",
    "CodeSize": 413,
    "Description": "",
    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2024-08-04T10:51:50.585+0000",
    "CodeSha256": "nciDUmm7f23oZxnzby4PM+8ud73Fhoy62JGfBHofW3U=",
    "Version": "$LATEST",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "972d7ae7-0212-4b87-9971-f63890593325",
    "State": "Pending",
    "StateReason": "The function is being created.",
    "StateReasonCode": "Creating",
    "PackageType": "Zip",
    "Architectures": [
        "x86_64"
    ],
    "EphemeralStorage": {
        "Size": 512
    },
    "SnapStart": {
        "ApplyOn": "None",
        "OptimizationStatus": "Off"
    },
    "RuntimeVersionConfig": {
        "RuntimeVersionArn": "arn:aws:lambda:us-east-1::runtime:d2da00eeedb26cf3d2faaca725b024098a35c6e8a9c894dfa7015d02f6659c0a"
    },
    "LoggingConfig": {
        "LogFormat": "Text",
        "LogGroup": "/aws/lambda/handson-lambda"
    }
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ARNの取得
[cloudshell-user@ip-10-134-11-244 ~]$ FUNCTION_ARN=$(
>     aws lambda list-functions \
>         --query "Functions[?FunctionName=='${FUNCTION_NAME}'].FunctionArn" \
>         --output text \
>         --region ${REGION}
> ) \
> && echo ${FUNCTION_ARN}
arn:aws:lambda:us-east-1:999999999999:function:handson-lambda
```
## API Gateway作成
:::note info
条件
- API名：handson-api
- APIエンドポイントタイプ：リージョン
- リージョン：バージニア北部
:::
### 変数設定
```bash:コマンド
# API名
API_NAME="handson-api" \
&& echo ${API_NAME}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # API名
[cloudshell-user@ip-10-134-11-244 ~]$ API_NAME="handson-api" \
> && echo ${API_NAME}
handson-api
```
### REST APIの作成
```bash:コマンド
# REST APIの作成
aws apigateway create-rest-api \
    --name ${API_NAME} \
    --endpoint-configuration types=REGIONAL \
    --region ${REGION}

```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # REST APIの作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws apigateway create-rest-api \
>     --name ${API_NAME} \
>     --endpoint-configuration types=REGIONAL \
>     --region ${REGION}
{
    "id": "4ad63asxjb",
    "name": "handson-api",
    "createdDate": "2024-08-04T10:52:48+00:00",
    "apiKeySource": "HEADER",
    "endpointConfiguration": {
        "types": [
            "REGIONAL"
        ]
    },
    "disableExecuteApiEndpoint": false,
    "rootResourceId": "3vdr2wkvof"
}
```
### IDの取得
```bash:コマンド
# API IDの取得
RESET_API_ID=$(
    aws apigateway get-rest-apis \
        --query "items[?name=='${API_NAME}'].id" \
        --region ${REGION} \
        --output text
) \
&& echo ${RESET_API_ID}

# ルートリソースIDの取得
PARENT_ID=$(
    aws apigateway get-resources \
        --rest-api-id ${RESET_API_ID} \
        --query "items[?path=='/'].id" \
        --region ${REGION} \
        --output text
) \
&& echo ${PARENT_ID}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # API IDの取得
[cloudshell-user@ip-10-134-11-244 ~]$ RESET_API_ID=$(
>     aws apigateway get-rest-apis \
>         --query "items[?name=='${API_NAME}'].id" \
>         --region ${REGION} \
>         --output text
> ) \
> && echo ${RESET_API_ID}
4ad63asxjb
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ルートリソースIDの取得
[cloudshell-user@ip-10-134-11-244 ~]$ PARENT_ID=$(
>     aws apigateway get-resources \
>         --rest-api-id ${RESET_API_ID} \
>         --query "items[?path=='/'].id" \
>         --region ${REGION} \
>         --output text
> ) \
> && echo ${PARENT_ID}
3vdr2wkvof
```
### GETメソッドの作成
:::note info
条件
- 総合タイプ：Lambda関数
- Lambda プロキシ総合の使用：あり
- Lambdaリージョン：バージニア北部
- Lambda関数：handson-lambda
- デフォルトタイムアウトの使用：あり
:::
```bash:コマンド
# GETメソッドの作成
aws apigateway put-method \
  --rest-api-id ${RESET_API_ID} \
  --resource-id ${PARENT_ID} \
  --http-method GET \
  --authorization-type NONE \
  --no-api-key-required \
  --request-parameters method.request.querystring.input_text=false \
  --region ${REGION}

# メソッドレスポンスの設定
aws apigateway put-method-response \
  --rest-api-id ${RESET_API_ID} \
  --resource-id ${PARENT_ID} \
  --http-method GET \
  --status-code 200 \
  --response-models application/json=Empty \
  --region ${REGION}

# 統合の設定
aws apigateway put-integration \
  --rest-api-id ${RESET_API_ID} \
  --resource-id ${PARENT_ID} \
  --http-method GET \
  --type AWS_PROXY \
  --integration-http-method POST \
  --uri arn:aws:apigateway:${REGION}:lambda:path/2015-03-31/functions/${FUNCTION_ARN}/invocations \
  --passthrough-behavior WHEN_NO_MATCH \
  --content-handling CONVERT_TO_TEXT \
  --timeout-in-millis 29000 \
  --region ${REGION}

# 統合レスポンスの設定
aws apigateway put-integration-response \
  --rest-api-id ${RESET_API_ID} \
  --resource-id ${PARENT_ID} \
  --http-method GET \
  --status-code 200 \
  --response-templates application/json="" \
  --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # GETメソッドの作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws apigateway put-method \
>   --rest-api-id ${RESET_API_ID} \
>   --resource-id ${PARENT_ID} \
>   --http-method GET \
>   --authorization-type NONE \
>   --no-api-key-required \
>   --request-parameters method.request.querystring.input_text=false \
>   --region ${REGION}
{
    "httpMethod": "GET",
    "authorizationType": "NONE",
    "apiKeyRequired": false,
    "requestParameters": {
        "method.request.querystring.input_text": false
    }
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # メソッドレスポンスの設定
[cloudshell-user@ip-10-134-11-244 ~]$ aws apigateway put-method-response \
>   --rest-api-id ${RESET_API_ID} \
>   --resource-id ${PARENT_ID} \
>   --http-method GET \
>   --status-code 200 \
>   --response-models application/json=Empty \
>   --region ${REGION}
{
    "statusCode": "200",
    "responseModels": {
        "application/json": "Empty"
    }
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # 統合の設定
[cloudshell-user@ip-10-134-11-244 ~]$ aws apigateway put-integration \
>   --rest-api-id ${RESET_API_ID} \
>   --resource-id ${PARENT_ID} \
>   --http-method GET \
>   --type AWS_PROXY \
>   --integration-http-method POST \
>   --uri arn:aws:apigateway:${REGION}:lambda:path/2015-03-31/functions/${FUNCTION_ARN}/invocations \
>   --passthrough-behavior WHEN_NO_MATCH \
>   --content-handling CONVERT_TO_TEXT \
>   --timeout-in-millis 29000 \
>   --region ${REGION}
{
    "type": "AWS_PROXY",
    "httpMethod": "POST",
    "uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:999999999999:function:handson-lambda/invocations",
    "passthroughBehavior": "WHEN_NO_MATCH",
    "contentHandling": "CONVERT_TO_TEXT",
    "timeoutInMillis": 29000,
    "cacheNamespace": "3vdr2wkvof",
    "cacheKeyParameters": []
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # 統合レスポンスの設定
[cloudshell-user@ip-10-134-11-244 ~]$ aws apigateway put-integration-response \
>   --rest-api-id ${RESET_API_ID} \
>   --resource-id ${PARENT_ID} \
>   --http-method GET \
>   --status-code 200 \
>   --response-templates application/json="" \
>   --region ${REGION}
{
    "statusCode": "200",
    "responseTemplates": {
        "application/json": null
    }
}
```
### デプロイ
```bash:コマンド
# 変数
STAGE_NAME="api" \
&& echo ${STAGE_NAME}

# デプロイ
aws apigateway create-deployment \
    --rest-api-id ${RESET_API_ID} \
    --stage-name ${STAGE_NAME} \
    --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # 変数
[cloudshell-user@ip-10-134-11-244 ~]$ STAGE_NAME="api" \
> && echo ${STAGE_NAME}
api
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # デプロイ
[cloudshell-user@ip-10-134-11-244 ~]$ aws apigateway create-deployment \
>     --rest-api-id ${RESET_API_ID} \
>     --stage-name ${STAGE_NAME} \
>     --region ${REGION}
{
    "id": "jcg2z7",
    "createdDate": "2024-08-04T10:54:14+00:00"
}
```
### Lambdaへの権限追加
```bash:コマンド
RESOURCE_PATH=$(
    aws apigateway get-resources \
        --rest-api-id ${RESET_API_ID} \
        --query items[].path \
        --output text \
        --region ${REGION}
) \
&& echo ${RESOURCE_PATH}

aws lambda add-permission \
    --function-name ${FUNCTION_NAME} \
    --statement-id ${FUNCTION_NAME}\
    --action 'lambda:InvokeFunction' \
    --principal apigateway.amazonaws.com \
    --source-arn arn:aws:execute-api:${REGION}:999999999999:${RESET_API_ID}/*/GET${RESOURCE_PATH} \
    --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # パスの取得
[cloudshell-user@ip-10-134-11-244 ~]$ RESOURCE_PATH=$(
>     aws apigateway get-resources \
>         --rest-api-id ${RESET_API_ID} \
>         --query items[].path \
>         --output text \
>         --region ${REGION}
> ) \
> && echo ${RESOURCE_PATH}
/
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # Lambdaへの権限追加
[cloudshell-user@ip-10-134-11-244 ~]$ aws lambda add-permission \
>     --function-name ${FUNCTION_NAME} \
>     --statement-id ${FUNCTION_NAME}\
>     --action 'lambda:InvokeFunction' \
>     --principal apigateway.amazonaws.com \
>     --source-arn arn:aws:execute-api:${REGION}:999999999999:${RESET_API_ID}/*/GET${RESOURCE_PATH} \
>     --region ${REGION}
{
    "Statement": "{\"Sid\":\"handson-lambda\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-east-1:999999999999:function:handson-lambda\",\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:us-east-1:999999999999:4ad63asxjb/*/GET/\"}}}"
}
```
## 通信確認 (API Gateway直)
```bash:コマンド
# input_textオプションをつけないとエラーになる
curl https://${RESET_API_ID}.execute-api.${REGION}.amazonaws.com/${STAGE_NAME}

# input_textオプションをつけると翻訳される(日本語をURLエンコードでしてから渡す)
encoded_query=$(echo -n 'こんにちは世界' | jq -s -R -r @uri) \
&& echo ${encoded_query}
curl https://${RESET_API_ID}.execute-api.${REGION}.amazonaws.com/${STAGE_NAME}?input_text=${encoded_query}

```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # input_textオプションをつけないとエラーになる
[cloudshell-user@ip-10-134-11-244 ~]$ curl https://${RESET_API_ID}.execute-api.${REGION}.amazonaws.com/${STAGE_NAME}
{"message": "Internal server error"}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # input_textオプションをつけると翻訳される(日本語をURLエンコードでしてから渡す)
[cloudshell-user@ip-10-134-11-244 ~]$ encoded_query=$(echo -n 'こんにちは世界' | jq -s -R -r @uri) \
> && echo ${encoded_query}
%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C
[cloudshell-user@ip-10-134-11-244 ~]$ curl https://${RESET_API_ID}.execute-api.${REGION}.amazonaws.com/${STAGE_NAME}?input_text=${encoded_query}
Hello world
```
# 07 Amazon CloudFrontのハンズオン その4 (動的コンテンツの配信設定②)
## オリジンリクエストポリシー作成
### 設定JSON
```bash:コマンド
# オリジンリクエストポリシー名
ORIGIN_REQUESTPOLICY_NAME="handson-originrequestpolicy" \
&& echo ${ORIGIN_REQUESTPOLICY_NAME}

# オリジンリクエストポリシー設定JSON
ORIGIN_REQUESTPOLICY_JSON=$(cat << EOF
{
    "Name": "${ORIGIN_REQUESTPOLICY_NAME}",
    "HeadersConfig": {
        "HeaderBehavior": "none"
    },
    "CookiesConfig": {
        "CookieBehavior": "none"
    },
    "QueryStringsConfig": {
        "QueryStringBehavior": "whitelist",
        "QueryStrings": {
            "Items": [
                "input_text"
            ],
            "Quantity": 1
        }
    }
}
EOF
) \
&& echo ${ORIGIN_REQUESTPOLICY_JSON}

# JSONフォーマットの確認
echo ${ORIGIN_REQUESTPOLICY_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # オリジンリクエストポリシー名
[cloudshell-user@ip-10-134-11-244 ~]$ ORIGIN_REQUESTPOLICY_NAME="handson-originrequestpolicy" \
> && echo ${ORIGIN_REQUESTPOLICY_NAME}
handson-originrequestpolicy
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # オリジンリクエストポリシー設定JSON
[cloudshell-user@ip-10-134-11-244 ~]$ ORIGIN_REQUESTPOLICY_JSON=$(cat << EOF
> {
>     "Name": "${ORIGIN_REQUESTPOLICY_NAME}",
>     "HeadersConfig": {
>         "HeaderBehavior": "none"
>     },
>     "CookiesConfig": {
>         "CookieBehavior": "none"
>     },
>     "QueryStringsConfig": {
>         "QueryStringBehavior": "whitelist",
>         "QueryStrings": {
>             "Items": [
>                 "input_text"
>             ],
>             "Quantity": 1
>         }
>     }
> }
> EOF
> ) \
> && echo ${ORIGIN_REQUESTPOLICY_JSON}
{ "Name": "handson-originrequestpolicy", "HeadersConfig": { "HeaderBehavior": "none" }, "CookiesConfig": { "CookieBehavior": "none" }, "QueryStringsConfig": { "QueryStringBehavior": "whitelist", "QueryStrings": { "Items": [ "input_text" ], "Quantity": 1 } } }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${ORIGIN_REQUESTPOLICY_JSON} | python -m json.tool
{
    "Name": "handson-originrequestpolicy",
    "HeadersConfig": {
        "HeaderBehavior": "none"
    },
    "CookiesConfig": {
        "CookieBehavior": "none"
    },
    "QueryStringsConfig": {
        "QueryStringBehavior": "whitelist",
        "QueryStrings": {
            "Items": [
                "input_text"
            ],
            "Quantity": 1
        }
    }
}
```
### オリジンリクエストポリシー設定
```bash:コマンド
# オリジンリクエストポリシー作成
aws cloudfront create-origin-request-policy \
    --origin-request-policy-config "${ORIGIN_REQUESTPOLICY_JSON}"

# オリジンリクエストポリシー名を指定してId取得
ORIGIN_REQUESTPOLICY_ID=$(
    aws cloudfront list-origin-request-policies  \
        --query "OriginRequestPolicyList.Items[?OriginRequestPolicy.OriginRequestPolicyConfig.Name=='${ORIGIN_REQUESTPOLICY_NAME}'].OriginRequestPolicy.Id" \
        --output text
) \
&& echo ${ORIGIN_REQUESTPOLICY_ID}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # オリジンリクエストポリシー作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront create-origin-request-policy \
>     --origin-request-policy-config "${ORIGIN_REQUESTPOLICY_JSON}"
{
    "Location": "https://cloudfront.amazonaws.com/2020-05-31/origin-request-policy/8f0c7698-7ec2-42b7-9155-f1e2bc9418d0",
    "ETag": "E23ZP02F085DFQ",
    "OriginRequestPolicy": {
        "Id": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0",
        "LastModifiedTime": "2024-08-04T11:13:29.856000+00:00",
        "OriginRequestPolicyConfig": {
            "Name": "handson-originrequestpolicy",
            "HeadersConfig": {
                "HeaderBehavior": "none"
            },
            "CookiesConfig": {
                "CookieBehavior": "none"
            },
            "QueryStringsConfig": {
                "QueryStringBehavior": "whitelist",
                "QueryStrings": {
                    "Quantity": 1,
                    "Items": [
                        "input_text"
                    ]
                }
            }
        }
    }
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # オリジンリクエストポリシー名を指定してId取得
[cloudshell-user@ip-10-134-11-244 ~]$ ORIGIN_REQUESTPOLICY_ID=$(
>     aws cloudfront list-origin-request-policies  \
>         --query "OriginRequestPolicyList.Items[?OriginRequestPolicy.OriginRequestPolicyConfig.Name=='${ORIGIN_REQUESTPOLICY_NAME}'].OriginRequestPolicy.Id" \
>         --output text
> ) \
> && echo ${ORIGIN_REQUESTPOLICY_ID}
8f0c7698-7ec2-42b7-9155-f1e2bc9418d0
```
## ディストリビューション変更
### オリジン設定JSON
```bash:コマンド
# オリジン設定JSON
ORIGIN_JSON=$(cat << EOF
{
    "Id": "${RESET_API_ID}.execute-api.${REGION}.amazonaws.com",
    "DomainName": "${RESET_API_ID}.execute-api.${REGION}.amazonaws.com",
    "OriginPath": "",
    "CustomHeaders": {
        "Quantity": 0
    },
    "CustomOriginConfig": {
        "HTTPPort": 80,
        "HTTPSPort": 443,
        "OriginProtocolPolicy": "https-only",
        "OriginSslProtocols": {
            "Quantity": 1,
            "Items": [
                "TLSv1.2"
            ]
        },
        "OriginReadTimeout": 30,
        "OriginKeepaliveTimeout": 5
    },
    "ConnectionAttempts": 3,
    "ConnectionTimeout": 10,
    "OriginShield": {
        "Enabled": false
    },
    "OriginAccessControlId": ""
}
EOF
) \
&& echo ${ORIGIN_JSON}

# JSONフォーマットの確認
echo ${ORIGIN_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # オリジン設定JSON
[cloudshell-user@ip-10-134-11-244 ~]$ ORIGIN_JSON=$(cat << EOF
> {
>     "Id": "${RESET_API_ID}.execute-api.${REGION}.amazonaws.com",
>     "DomainName": "${RESET_API_ID}.execute-api.${REGION}.amazonaws.com",
>     "OriginPath": "",
>     "CustomHeaders": {
>         "Quantity": 0
>     },
>     "CustomOriginConfig": {
>         "HTTPPort": 80,
>         "HTTPSPort": 443,
>         "OriginProtocolPolicy": "https-only",
>         "OriginSslProtocols": {
>             "Quantity": 1,
>             "Items": [
>                 "TLSv1.2"
>             ]
>         },
>         "OriginReadTimeout": 30,
>         "OriginKeepaliveTimeout": 5
>     },
>     "ConnectionAttempts": 3,
>     "ConnectionTimeout": 10,
>     "OriginShield": {
>         "Enabled": false
>     },
>     "OriginAccessControlId": ""
> }
> EOF
> ) \
> && echo ${ORIGIN_JSON}
{ "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, "OriginProtocolPolicy": "https-only", "OriginSslProtocols": { "Quantity": 1, "Items": [ "TLSv1.2" ] }, "OriginReadTimeout": 30, "OriginKeepaliveTimeout": 5 }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "" }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${ORIGIN_JSON} | python -m json.tool
{
    "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
    "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
    "OriginPath": "",
    "CustomHeaders": {
        "Quantity": 0
    },
    "CustomOriginConfig": {
        "HTTPPort": 80,
        "HTTPSPort": 443,
        "OriginProtocolPolicy": "https-only",
        "OriginSslProtocols": {
            "Quantity": 1,
            "Items": [
                "TLSv1.2"
            ]
        },
        "OriginReadTimeout": 30,
        "OriginKeepaliveTimeout": 5
    },
    "ConnectionAttempts": 3,
    "ConnectionTimeout": 10,
    "OriginShield": {
        "Enabled": false
    },
    "OriginAccessControlId": ""
}
```
### ビヘイビア設定JSON
:::note info
条件
- パスパターン：/${STAGE_NAME}/*
- Redirect HTTP to HTTPS
- キャッシュポリシー：CachingDisabled
:::
```bash:コマンド
# ビヘイビア設定JSON
BEHAVIOR_JSON=$(cat << EOF
{
    "PathPattern": "/api",
    "TargetOriginId": "${RESET_API_ID}.execute-api.${REGION}.amazonaws.com",
    "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": true,
    "LambdaFunctionAssociations": {
        "Quantity": 0
    },
    "FunctionAssociations": {
        "Quantity": 0
    },
    "FieldLevelEncryptionId": "",
    "CachePolicyId": "${MANAGED_CACHING_DISABLED_ID}",
    "OriginRequestPolicyId": "${ORIGIN_REQUESTPOLICY_ID}"
}
EOF
) \
&& echo ${BEHAVIOR_JSON}

# JSONフォーマットの確認
echo ${BEHAVIOR_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ビヘイビア設定JSON
[cloudshell-user@ip-10-134-11-244 ~]$ BEHAVIOR_JSON=$(cat << EOF
> {
>     "PathPattern": "/api",
>     "TargetOriginId": "${RESET_API_ID}.execute-api.${REGION}.amazonaws.com",
>     "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": true,
>     "LambdaFunctionAssociations": {
>         "Quantity": 0
>     },
>     "FunctionAssociations": {
>         "Quantity": 0
>     },
>     "FieldLevelEncryptionId": "",
>     "CachePolicyId": "${MANAGED_CACHING_DISABLED_ID}",
>     "OriginRequestPolicyId": "${ORIGIN_REQUESTPOLICY_ID}"
> }
> EOF
> ) \
> && echo ${BEHAVIOR_JSON}
{ "PathPattern": "/api", "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad", "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0" }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${BEHAVIOR_JSON} | python -m json.tool
{
    "PathPattern": "/api",
    "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
    "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": true,
    "LambdaFunctionAssociations": {
        "Quantity": 0
    },
    "FunctionAssociations": {
        "Quantity": 0
    },
    "FieldLevelEncryptionId": "",
    "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
    "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0"
}
```
### ディストリビューションJSON 
```bash:コマンド
# ディストリビューション変更用JSON
CONFIG=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        --query "DistributionConfig" \
        | jq --argjson origin_after "${ORIGIN_JSON}" '.Origins.Items += [$origin_after]' \
        | jq '.Origins.Quantity += 1' \
        | jq --argjson behavior_after "${BEHAVIOR_JSON}" '.CacheBehaviors.Items += [$behavior_after]' \
        | jq '.CacheBehaviors.Quantity += 1'
) \
&& echo ${CONFIG}

# JSONフォーマットの確認
echo ${CONFIG} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ディストリビューション変更用JSON
[cloudshell-user@ip-10-134-11-244 ~]$ CONFIG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query "DistributionConfig" \
>         | jq --argjson origin_after "${ORIGIN_JSON}" '.Origins.Items += [$origin_after]' \
>         | jq '.Origins.Quantity += 1' \
>         | jq --argjson behavior_after "${BEHAVIOR_JSON}" '.CacheBehaviors.Items += [$behavior_after]' \
>         | jq '.CacheBehaviors.Quantity += 1'
> ) \
> && echo ${CONFIG}
{ "CallerReference": "cli-1722767554-44223", "Aliases": { "Quantity": 0 }, "DefaultRootObject": "index.html", "Origins": { "Quantity": 2, "Items": [ { "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "S3OriginConfig": { "OriginAccessIdentity": "" }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "E2G9MJEEXTOJC1" }, { "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, "OriginProtocolPolicy": "https-only", "OriginSslProtocols": { "Quantity": 1, "Items": [ "TLSv1.2" ] }, "OriginReadTimeout": 30, "OriginKeepaliveTimeout": 5 }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "" } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" }, "CacheBehaviors": { "Quantity": 2, "Items": [ { "PathPattern": "/static/*", "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf" }, { "PathPattern": "/api", "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad", "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0" } ] }, "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 }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${CONFIG} | python -m json.tool
{
    "CallerReference": "cli-1722767554-44223",
    "Aliases": {
        "Quantity": 0
    },
    "DefaultRootObject": "index.html",
    "Origins": {
        "Quantity": 2,
        "Items": [
            {
                "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "S3OriginConfig": {
                    "OriginAccessIdentity": ""
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": "E2G9MJEEXTOJC1"
            },
            {
                "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "CustomOriginConfig": {
                    "HTTPPort": 80,
                    "HTTPSPort": 443,
                    "OriginProtocolPolicy": "https-only",
                    "OriginSslProtocols": {
                        "Quantity": 1,
                        "Items": [
                            "TLSv1.2"
                        ]
                    },
                    "OriginReadTimeout": 30,
                    "OriginKeepaliveTimeout": 5
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": ""
            }
        ]
    },
    "OriginGroups": {
        "Quantity": 0
    },
    "DefaultCacheBehavior": {
        "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
        "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": true,
        "LambdaFunctionAssociations": {
            "Quantity": 0
        },
        "FunctionAssociations": {
            "Quantity": 0
        },
        "FieldLevelEncryptionId": "",
        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
    },
    "CacheBehaviors": {
        "Quantity": 2,
        "Items": [
            {
                "PathPattern": "/static/*",
                "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf"
            },
            {
                "PathPattern": "/api",
                "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
                "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0"
            }
        ]
    },
    "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:コマンド
# 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}" \
    --if-match ${ETAG} \
    --no-cli-pager
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ETagを取得
[cloudshell-user@ip-10-134-11-244 ~]$ ETAG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
E3H7EIKSZ5KXEF
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # CloudFrontディストリビューションの設定を更新
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront update-distribution \
>     --id ${DISTRIBUTION_ID} \
>     --distribution-config "${CONFIG}" \
>     --if-match ${ETAG} \
>     --no-cli-pager
{
    "ETag": "E3EX4K76BA19NB",
    "Distribution": {
        "Id": "EIN33GD07JLDT",
        "ARN": "arn:aws:cloudfront::999999999999:distribution/EIN33GD07JLDT",
        "Status": "InProgress",
        "LastModifiedTime": "2024-08-04T11:16:17.725000+00:00",
        "InProgressInvalidationBatches": 0,
        "DomainName": "d18sbbratjvl6c.cloudfront.net",
        "ActiveTrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ActiveTrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "DistributionConfig": {
            "CallerReference": "cli-1722767554-44223",
            "Aliases": {
                "Quantity": 0
            },
            "DefaultRootObject": "index.html",
            "Origins": {
                "Quantity": 2,
                "Items": [
                    {
                        "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                        "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "S3OriginConfig": {
                            "OriginAccessIdentity": ""
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": "E2G9MJEEXTOJC1"
                    },
                    {
                        "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                        "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "CustomOriginConfig": {
                            "HTTPPort": 80,
                            "HTTPSPort": 443,
                            "OriginProtocolPolicy": "https-only",
                            "OriginSslProtocols": {
                                "Quantity": 1,
                                "Items": [
                                    "TLSv1.2"
                                ]
                            },
                            "OriginReadTimeout": 30,
                            "OriginKeepaliveTimeout": 5
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": ""
                    }
                ]
            },
            "OriginGroups": {
                "Quantity": 0
            },
            "DefaultCacheBehavior": {
                "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
            },
            "CacheBehaviors": {
                "Quantity": 2,
                "Items": [
                    {
                        "PathPattern": "/static/*",
                        "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                        "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": true,
                        "LambdaFunctionAssociations": {
                            "Quantity": 0
                        },
                        "FunctionAssociations": {
                            "Quantity": 0
                        },
                        "FieldLevelEncryptionId": "",
                        "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf"
                    },
                    {
                        "PathPattern": "/api",
                        "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                        "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": true,
                        "LambdaFunctionAssociations": {
                            "Quantity": 0
                        },
                        "FunctionAssociations": {
                            "Quantity": 0
                        },
                        "FieldLevelEncryptionId": "",
                        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
                        "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0"
                    }
                ]
            },
            "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
        }
    }
}
```
## 通信確認 (CloudFront経由)
```bash:コマンド
# input_textオプションをつけないとエラーになる
curl https://${DISTRIBUTION_DOMAINNAME}/${STAGE_NAME}

# input_textオプションをつけると翻訳される(日本語をURLエンコードでしてから渡す)
encoded_query=$(echo -n 'こんにちは世界' | jq -s -R -r @uri) \
&& echo ${encoded_query}
curl https://${DISTRIBUTION_DOMAINNAME}/${STAGE_NAME}?input_text=${encoded_query}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # input_textオプションをつけないとエラーになる
[cloudshell-user@ip-10-134-11-244 ~]$ curl https://${DISTRIBUTION_DOMAINNAME}/${STAGE_NAME}
{"message": "Internal server error"}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # input_textオプションをつけると翻訳される(日本語をURLエンコードでしてから渡す)
[cloudshell-user@ip-10-134-11-244 ~]$ encoded_query=$(echo -n 'こんにちは世界' | jq -s -R -r @uri) \
> && echo ${encoded_query}
%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C
[cloudshell-user@ip-10-134-11-244 ~]$ curl https://${DISTRIBUTION_DOMAINNAME}/${STAGE_NAME}?input_text=${encoded_query}
Hello world
```
# 09 AWS WAFのハンズオン
## Web ACL 作成
:::note info
条件
<INS>Web ACL details</INS>
- Resource type：Amazon CloudFront destributions
- Name：handson-waf
- CloudWatch metric name：handson-waf

<INS>Rule</INS>
<INS>Add my own rules and rule groups</INS>
- Rule type：Rule builder
- Name：handson-rule
- Type：Regular rule
- If a request：matches the statement
- Statement：Originates from country in
- Country codes：Japan
- IP address to use to determine the country of origin：Source IP address
- Action：Block

<INS>Default web ACL action for requests that don't match any rules</INS>
- Default action：Allow

<INS>Amazon CloudWatch metrics</INS>
- Rules：handson-rule
- CloudWatch metric name：handson-rule

<INS>Request sampling options</INS>
- Options：Enable samled requests
:::
### 独自ルールJSON
```bash:コマンド
# ルール名
ACL_RULE_NAME="handson-rule" \
&& echo ${ACL_RULE_NAME}

# my own rules and rule groups
ACL_RULE_JSON=$(cat << EOF
{
    "Name": "${ACL_RULE_NAME}",
    "Priority": 0,
    "Action": {
        "Block": {}
    },
    "Statement": {
        "GeoMatchStatement": {
            "CountryCodes": ["JP"]
        }
    },
    "VisibilityConfig": {
        "SampledRequestsEnabled": true,
        "CloudWatchMetricsEnabled": true,
        "MetricName": "${ACL_RULE_NAME}"
    }
}
EOF
) \
&& echo ${ACL_RULE_JSON}

# JSONフォーマットの確認
echo ${ACL_RULE_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ルール名
[cloudshell-user@ip-10-134-11-244 ~]$ ACL_RULE_NAME="handson-rule" \
> && echo ${ACL_RULE_NAME}
handson-rule
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # my own rules and rule groups
[cloudshell-user@ip-10-134-11-244 ~]$ ACL_RULE_JSON=$(cat << EOF
> {
>     "Name": "${ACL_RULE_NAME}",
>     "Priority": 0,
>     "Action": {
>         "Block": {}
>     },
>     "Statement": {
>         "GeoMatchStatement": {
>             "CountryCodes": ["JP"]
>         }
>     },
>     "VisibilityConfig": {
>         "SampledRequestsEnabled": true,
>         "CloudWatchMetricsEnabled": true,
>         "MetricName": "${ACL_RULE_NAME}"
>     }
> }
> EOF
> ) \
> && echo ${ACL_RULE_JSON}
{ "Name": "handson-rule", "Priority": 0, "Action": { "Block": {} }, "Statement": { "GeoMatchStatement": { "CountryCodes": ["JP"] } }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "handson-rule" } }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${ACL_RULE_JSON} | python -m json.tool
{
    "Name": "handson-rule",
    "Priority": 0,
    "Action": {
        "Block": {}
    },
    "Statement": {
        "GeoMatchStatement": {
            "CountryCodes": [
                "JP"
            ]
        }
    },
    "VisibilityConfig": {
        "SampledRequestsEnabled": true,
        "CloudWatchMetricsEnabled": true,
        "MetricName": "handson-rule"
    }
}
```
### Web ACL作成
```bash:コマンド
# 変数
WEB_ACL_NAME="handson-waf" \
&& echo ${WEB_ACL_NAME}

# Web ACL作成
aws wafv2 create-web-acl \
    --name ${WEB_ACL_NAME} \
    --scope CLOUDFRONT \
    --default-action Allow={} \
    --rules "[${ACL_RULE}]" \
    --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=handson-rule \
    --region ${REGION}

# ID取得
WEB_ACL_ID=$(
    aws wafv2 list-web-acls \
        --scope CLOUDFRONT \
        --region ${REGION} \
        --query "WebACLs[?Name=='${WEB_ACL_NAME}'].Id" \
        --output text
) \
&& echo ${WEB_ACL_ID}

# ARN取得
WEB_ACL_ARN=$(
    aws wafv2 list-web-acls \
        --scope CLOUDFRONT \
        --region ${REGION} \
        --query "WebACLs[?Name=='${WEB_ACL_NAME}'].ARN" \
        --output text
) \
&& echo ${WEB_ACL_ARN}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # 変数
[cloudshell-user@ip-10-134-11-244 ~]$ WEB_ACL_NAME="handson-waf" \
> && echo ${WEB_ACL_NAME}
handson-waf
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # Web ACL作成
[cloudshell-user@ip-10-134-11-244 ~]$ aws wafv2 create-web-acl \
>     --name ${WEB_ACL_NAME} \
>     --scope CLOUDFRONT \
>     --default-action Allow={} \
>     --rules "[${ACL_RULE_JSON}]" \
>     --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=handson-rule \
>     --region ${REGION}
{
    "Summary": {
        "Name": "handson-waf",
        "Id": "a471ff68-5aba-411d-b2af-7eb66f520b04",
        "Description": "",
        "LockToken": "55c562cc-403a-4c6e-a8d9-7fdba6a7178d",
        "ARN": "arn:aws:wafv2:us-east-1:999999999999:global/webacl/handson-waf/a471ff68-5aba-411d-b2af-7eb66f520b04"
    }
}
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ID取得
[cloudshell-user@ip-10-134-11-244 ~]$ WEB_ACL_ID=$(
>     aws wafv2 list-web-acls \
>         --scope CLOUDFRONT \
>         --region ${REGION} \
>         --query "WebACLs[?Name=='${WEB_ACL_NAME}'].Id" \
>         --output text
> ) \
> && echo ${WEB_ACL_ID}
a471ff68-5aba-411d-b2af-7eb66f520b04
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ARN取得
[cloudshell-user@ip-10-134-11-244 ~]$ WEB_ACL_ARN=$(
>     aws wafv2 list-web-acls \
>         --scope CLOUDFRONT \
>         --region ${REGION} \
>         --query "WebACLs[?Name=='${WEB_ACL_NAME}'].ARN" \
>         --output text
> ) \
> && echo ${WEB_ACL_ARN}
arn:aws:wafv2:us-east-1:999999999999:global/webacl/handson-waf/a471ff68-5aba-411d-b2af-7eb66f520b04
```
## CloudFrontディストリビューションにWeb ACLを関連付け
### ディストリビューション変更用JSON
```bash:コマンド
# ディストリビューション変更用JSON
CONFIG=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        --query "DistributionConfig" \
        | jq --arg web_acl "${WEB_ACL_ARN}" '."WebACLId" = $web_acl'
) \
&& echo ${CONFIG}

# JSONフォーマットの確認
echo ${CONFIG} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ディストリビューション変更用JSON
[cloudshell-user@ip-10-134-11-244 ~]$ CONFIG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query "DistributionConfig" \
>         | jq --arg web_acl "${WEB_ACL_ARN}" '."WebACLId" = $web_acl'
> ) \
> && echo ${CONFIG}
{ "CallerReference": "cli-1722767554-44223", "Aliases": { "Quantity": 0 }, "DefaultRootObject": "index.html", "Origins": { "Quantity": 2, "Items": [ { "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "S3OriginConfig": { "OriginAccessIdentity": "" }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "E2G9MJEEXTOJC1" }, { "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, "OriginProtocolPolicy": "https-only", "OriginSslProtocols": { "Quantity": 1, "Items": [ "TLSv1.2" ] }, "OriginReadTimeout": 30, "OriginKeepaliveTimeout": 5 }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "" } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" }, "CacheBehaviors": { "Quantity": 2, "Items": [ { "PathPattern": "/static/*", "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf" }, { "PathPattern": "/api", "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad", "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0" } ] }, "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": "arn:aws:wafv2:us-east-1:999999999999:global/webacl/handson-waf/a471ff68-5aba-411d-b2af-7eb66f520b04", "HttpVersion": "http2", "IsIPV6Enabled": true, "ContinuousDeploymentPolicyId": "", "Staging": false }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${CONFIG} | python -m json.tool
{
    "CallerReference": "cli-1722767554-44223",
    "Aliases": {
        "Quantity": 0
    },
    "DefaultRootObject": "index.html",
    "Origins": {
        "Quantity": 2,
        "Items": [
            {
                "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "S3OriginConfig": {
                    "OriginAccessIdentity": ""
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": "E2G9MJEEXTOJC1"
            },
            {
                "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "CustomOriginConfig": {
                    "HTTPPort": 80,
                    "HTTPSPort": 443,
                    "OriginProtocolPolicy": "https-only",
                    "OriginSslProtocols": {
                        "Quantity": 1,
                        "Items": [
                            "TLSv1.2"
                        ]
                    },
                    "OriginReadTimeout": 30,
                    "OriginKeepaliveTimeout": 5
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": ""
            }
        ]
    },
    "OriginGroups": {
        "Quantity": 0
    },
    "DefaultCacheBehavior": {
        "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
        "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": true,
        "LambdaFunctionAssociations": {
            "Quantity": 0
        },
        "FunctionAssociations": {
            "Quantity": 0
        },
        "FieldLevelEncryptionId": "",
        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
    },
    "CacheBehaviors": {
        "Quantity": 2,
        "Items": [
            {
                "PathPattern": "/static/*",
                "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf"
            },
            {
                "PathPattern": "/api",
                "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
                "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0"
            }
        ]
    },
    "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": "arn:aws:wafv2:us-east-1:999999999999:global/webacl/handson-waf/a471ff68-5aba-411d-b2af-7eb66f520b04",
    "HttpVersion": "http2",
    "IsIPV6Enabled": true,
    "ContinuousDeploymentPolicyId": "",
    "Staging": false
}
```
### ディストリビューション変更適用
```bash:コマンド
# ETagを取得
ETAG=$(
    aws cloudfront get-distribution-config \
        --id ${DISTRIBUTION_ID} \
        --query ETag \
        --output text
) \
&& echo ${ETAG}

# CloudFrontディストリビューションにWeb ACLを関連付け
aws cloudfront update-distribution \
    --id ${DISTRIBUTION_ID} \
    --distribution-config "${CONFIG}" \
    --if-match ${ETAG} \
    --no-cli-pager
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ETagを取得
[cloudshell-user@ip-10-134-11-244 ~]$ ETAG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
E3EX4K76BA19NB
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # CloudFrontディストリビューションにWeb ACLを関連付け
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront update-distribution \
>     --id ${DISTRIBUTION_ID} \
>     --distribution-config "${CONFIG}" \
>     --if-match ${ETAG} \
>     --no-cli-pager
{
    "ETag": "E1FXQ683ZR0G6S",
    "Distribution": {
        "Id": "EIN33GD07JLDT",
        "ARN": "arn:aws:cloudfront::999999999999:distribution/EIN33GD07JLDT",
        "Status": "InProgress",
        "LastModifiedTime": "2024-08-04T11:22:48.237000+00:00",
        "InProgressInvalidationBatches": 0,
        "DomainName": "d18sbbratjvl6c.cloudfront.net",
        "ActiveTrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ActiveTrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "DistributionConfig": {
            "CallerReference": "cli-1722767554-44223",
            "Aliases": {
                "Quantity": 0
            },
            "DefaultRootObject": "index.html",
            "Origins": {
                "Quantity": 2,
                "Items": [
                    {
                        "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                        "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "S3OriginConfig": {
                            "OriginAccessIdentity": ""
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": "E2G9MJEEXTOJC1"
                    },
                    {
                        "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                        "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "CustomOriginConfig": {
                            "HTTPPort": 80,
                            "HTTPSPort": 443,
                            "OriginProtocolPolicy": "https-only",
                            "OriginSslProtocols": {
                                "Quantity": 1,
                                "Items": [
                                    "TLSv1.2"
                                ]
                            },
                            "OriginReadTimeout": 30,
                            "OriginKeepaliveTimeout": 5
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": ""
                    }
                ]
            },
            "OriginGroups": {
                "Quantity": 0
            },
            "DefaultCacheBehavior": {
                "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
            },
            "CacheBehaviors": {
                "Quantity": 2,
                "Items": [
                    {
                        "PathPattern": "/static/*",
                        "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                        "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": true,
                        "LambdaFunctionAssociations": {
                            "Quantity": 0
                        },
                        "FunctionAssociations": {
                            "Quantity": 0
                        },
                        "FieldLevelEncryptionId": "",
                        "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf"
                    },
                    {
                        "PathPattern": "/api",
                        "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                        "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": true,
                        "LambdaFunctionAssociations": {
                            "Quantity": 0
                        },
                        "FunctionAssociations": {
                            "Quantity": 0
                        },
                        "FieldLevelEncryptionId": "",
                        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
                        "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0"
                    }
                ]
            },
            "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": "arn:aws:wafv2:us-east-1:999999999999:global/webacl/handson-waf/a471ff68-5aba-411d-b2af-7eb66f520b04",
            "HttpVersion": "http2",
            "IsIPV6Enabled": true,
            "ContinuousDeploymentPolicyId": "",
            "Staging": false
        }
    }
}
```
## 通信確認
### 東京リージョン
```bash:コマンド
# 東京リージョンのCloudShellから実施 (WAFによってブロック(403 ERROR)になる)
# input_textオプションをつけると翻訳される(日本語をURLエンコードでしてから渡す)
encoded_query=$(echo -n 'こんにちは世界' | jq -s -R -r @uri) \
&& echo ${encoded_query}
echo "https://${DISTRIBUTION_DOMAINNAME}/${STAGE_NAME}?input_text=${encoded_query}"

curl https://${DISTRIBUTION_DOMAINNAME}/${STAGE_NAME}?input_text=${encoded_query}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # 東京リージョンのCloudShellから実施 (WAFによってブロック(403 ERROR)になる)
[cloudshell-user@ip-10-134-11-244 ~]$ # input_textオプションをつけると翻訳される(日本語をURLエンコードでしてから渡す)
[cloudshell-user@ip-10-134-11-244 ~]$ encoded_query=$(echo -n 'こんにちは世界' | jq -s -R -r @uri) \
> && echo ${encoded_query}
%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C
[cloudshell-user@ip-10-134-11-244 ~]$ echo "https://${DISTRIBUTION_DOMAINNAME}/${STAGE_NAME}?input_text=${encoded_query}"
https://d18sbbratjvl6c.cloudfront.net/api?input_text=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ curl https://${DISTRIBUTION_DOMAINNAME}/${STAGE_NAME}?input_text=${encoded_query}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>403 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Request blocked.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: w627KZyxEfPMufk0OQAimR6E1Jx-h1OX1Id-kVon6oJ4l_eNNzq7kA==
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>
```
### バージニア北部リージョン
:::note warn
東京リージョンのCloudShellで実行した同じURLをバージニア北部リージョンから実施
:::
```bash:コマンド
# バージニア北部リージョンのCloudShellから実施 (アクセス可能)
curl https://d18sbbratjvl6c.cloudfront.net/api?input_text=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C
```
```bash:出力
[cloudshell-user@ip-10-130-92-135 ~]$ # バージニア北部リージョンのCloudShellから実施 (アクセス可能)
[cloudshell-user@ip-10-130-92-135 ~]$ curl https://d18sbbratjvl6c.cloudfront.net/api?input_text=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C
Hello world
```
## Web ACL追加 (マネージメントルール)
:::note info
条件
Add managed rule groups：Core rule set
:::
### マネージドルールJSON
```bash:コマンド
# マネージドルール (CoreRuleSet)
ACL_CORE_RULE_SET_JSON=$(cat << EOF
{
  "Name": "AWS-AWSManagedRulesCommonRuleSet",
  "Priority": 1,
  "OverrideAction": {
    "None": {}
  },
  "Statement": {
    "ManagedRuleGroupStatement": {
      "VendorName": "AWS",
      "Name": "AWSManagedRulesCommonRuleSet"
    }
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "AWS-AWSManagedRulesCommonRuleSet"
  }
}
EOF
) \
&& echo ${ACL_CORE_RULE_SET_JSON}

# JSONフォーマットの確認
echo ${ACL_CORE_RULE_SET_JSON} | python -m json.tool
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # マネージドルール (CoreRuleSet)
[cloudshell-user@ip-10-134-11-244 ~]$ ACL_CORE_RULE_SET_JSON=$(cat << EOF
> {
>   "Name": "AWS-AWSManagedRulesCommonRuleSet",
>   "Priority": 1,
>   "OverrideAction": {
>     "None": {}
>   },
>   "Statement": {
>     "ManagedRuleGroupStatement": {
>       "VendorName": "AWS",
>       "Name": "AWSManagedRulesCommonRuleSet"
>     }
>   },
>   "VisibilityConfig": {
>     "SampledRequestsEnabled": true,
>     "CloudWatchMetricsEnabled": true,
>     "MetricName": "AWS-AWSManagedRulesCommonRuleSet"
>   }
> }
> EOF
> ) \
> && echo ${ACL_CORE_RULE_SET_JSON}
{ "Name": "AWS-AWSManagedRulesCommonRuleSet", "Priority": 1, "OverrideAction": { "None": {} }, "Statement": { "ManagedRuleGroupStatement": { "VendorName": "AWS", "Name": "AWSManagedRulesCommonRuleSet" } }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "AWS-AWSManagedRulesCommonRuleSet" } }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${ACL_CORE_RULE_SET_JSON} | python -m json.tool
{
    "Name": "AWS-AWSManagedRulesCommonRuleSet",
    "Priority": 1,
    "OverrideAction": {
        "None": {}
    },
    "Statement": {
        "ManagedRuleGroupStatement": {
            "VendorName": "AWS",
            "Name": "AWSManagedRulesCommonRuleSet"
        }
    },
    "VisibilityConfig": {
        "SampledRequestsEnabled": true,
        "CloudWatchMetricsEnabled": true,
        "MetricName": "AWS-AWSManagedRulesCommonRuleSet"
    }
}
```
### マネージドルール追加
```bash:コマンド
# マネージドルール (CoreRuleSet) 追加
WAFV2_LOCKTOKEN=$(
    aws wafv2 get-web-acl \
        --name handson-waf \
        --scope CLOUDFRONT \
        --id ${WEB_ACL_ID} \
        --no-cli-pager \
        --region ${REGION} \
        --query LockToken \
        --output text
) \
&& echo ${WAFV2_LOCKTOKEN}

aws wafv2 update-web-acl \
  --name handson-waf \
  --scope CLOUDFRONT \
  --id ${WEB_ACL_ID} \
  --lock-token ${WAFV2_LOCKTOKEN} \
  --default-action Allow={} \
  --rules "[${ACL_RULE_JSON},${ACL_CORE_RULE_SET_JSON}]" \
  --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=handson-waf \
  --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # マネージドルール (CoreRuleSet) 追加
[cloudshell-user@ip-10-134-11-244 ~]$ WAFV2_LOCKTOKEN=$(
>     aws wafv2 get-web-acl \
>         --name handson-waf \
>         --scope CLOUDFRONT \
>         --id ${WEB_ACL_ID} \
>         --no-cli-pager \
>         --region ${REGION} \
>         --query LockToken \
>         --output text
> ) \
> && echo ${WAFV2_LOCKTOKEN}
55c562cc-403a-4c6e-a8d9-7fdba6a7178d
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ aws wafv2 update-web-acl \
>   --name handson-waf \
>   --scope CLOUDFRONT \
>   --id ${WEB_ACL_ID} \
>   --lock-token ${WAFV2_LOCKTOKEN} \
>   --default-action Allow={} \
>   --rules "[${ACL_RULE_JSON},${ACL_CORE_RULE_SET_JSON}]" \
>   --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=handson-waf \
>   --region ${REGION}
{
    "NextLockToken": "e31659be-da5b-4393-bce2-256623335626"
}
```
# 10 シリーズのまとめ、リソースの削除
## Amazon 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-134-11-244 ~]$ # ディストリビューション無効化用JSON
[cloudshell-user@ip-10-134-11-244 ~]$ DELL_CONFIG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         | jq .DistributionConfig \
>         | jq '.Enabled = false'
> ) \
> && echo ${DELL_CONFIG}
{ "CallerReference": "cli-1722767554-44223", "Aliases": { "Quantity": 0 }, "DefaultRootObject": "index.html", "Origins": { "Quantity": 2, "Items": [ { "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "S3OriginConfig": { "OriginAccessIdentity": "" }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "E2G9MJEEXTOJC1" }, { "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, "OriginProtocolPolicy": "https-only", "OriginSslProtocols": { "Quantity": 1, "Items": [ "TLSv1.2" ] }, "OriginReadTimeout": 30, "OriginKeepaliveTimeout": 5 }, "ConnectionAttempts": 3, "ConnectionTimeout": 10, "OriginShield": { "Enabled": false }, "OriginAccessControlId": "" } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" }, "CacheBehaviors": { "Quantity": 2, "Items": [ { "PathPattern": "/static/*", "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf" }, { "PathPattern": "/api", "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com", "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": true, "LambdaFunctionAssociations": { "Quantity": 0 }, "FunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "", "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad", "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0" } ] }, "CustomErrorResponses": { "Quantity": 0 }, "Comment": "", "Logging": { "Enabled": false, "IncludeCookies": false, "Bucket": "", "Prefix": "" }, "PriceClass": "PriceClass_All", "Enabled": false, "ViewerCertificate": { "CloudFrontDefaultCertificate": true, "SSLSupportMethod": "vip", "MinimumProtocolVersion": "TLSv1", "CertificateSource": "cloudfront" }, "Restrictions": { "GeoRestriction": { "RestrictionType": "none", "Quantity": 0 } }, "WebACLId": "arn:aws:wafv2:us-east-1:999999999999:global/webacl/handson-waf/a471ff68-5aba-411d-b2af-7eb66f520b04", "HttpVersion": "http2", "IsIPV6Enabled": true, "ContinuousDeploymentPolicyId": "", "Staging": false }
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # JSONフォーマットの確認
[cloudshell-user@ip-10-134-11-244 ~]$ echo ${DELL_CONFIG} | python -m json.tool
{
    "CallerReference": "cli-1722767554-44223",
    "Aliases": {
        "Quantity": 0
    },
    "DefaultRootObject": "index.html",
    "Origins": {
        "Quantity": 2,
        "Items": [
            {
                "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "S3OriginConfig": {
                    "OriginAccessIdentity": ""
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": "E2G9MJEEXTOJC1"
            },
            {
                "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                "OriginPath": "",
                "CustomHeaders": {
                    "Quantity": 0
                },
                "CustomOriginConfig": {
                    "HTTPPort": 80,
                    "HTTPSPort": 443,
                    "OriginProtocolPolicy": "https-only",
                    "OriginSslProtocols": {
                        "Quantity": 1,
                        "Items": [
                            "TLSv1.2"
                        ]
                    },
                    "OriginReadTimeout": 30,
                    "OriginKeepaliveTimeout": 5
                },
                "ConnectionAttempts": 3,
                "ConnectionTimeout": 10,
                "OriginShield": {
                    "Enabled": false
                },
                "OriginAccessControlId": ""
            }
        ]
    },
    "OriginGroups": {
        "Quantity": 0
    },
    "DefaultCacheBehavior": {
        "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
        "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": true,
        "LambdaFunctionAssociations": {
            "Quantity": 0
        },
        "FunctionAssociations": {
            "Quantity": 0
        },
        "FieldLevelEncryptionId": "",
        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
    },
    "CacheBehaviors": {
        "Quantity": 2,
        "Items": [
            {
                "PathPattern": "/static/*",
                "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf"
            },
            {
                "PathPattern": "/api",
                "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
                "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0"
            }
        ]
    },
    "CustomErrorResponses": {
        "Quantity": 0
    },
    "Comment": "",
    "Logging": {
        "Enabled": false,
        "IncludeCookies": false,
        "Bucket": "",
        "Prefix": ""
    },
    "PriceClass": "PriceClass_All",
    "Enabled": false,
    "ViewerCertificate": {
        "CloudFrontDefaultCertificate": true,
        "SSLSupportMethod": "vip",
        "MinimumProtocolVersion": "TLSv1",
        "CertificateSource": "cloudfront"
    },
    "Restrictions": {
        "GeoRestriction": {
            "RestrictionType": "none",
            "Quantity": 0
        }
    },
    "WebACLId": "arn:aws:wafv2:us-east-1:999999999999:global/webacl/handson-waf/a471ff68-5aba-411d-b2af-7eb66f520b04",
    "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} \
    --region ${REGION} \
    --no-cli-pager
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ETagを取得
[cloudshell-user@ip-10-134-11-244 ~]$ ETAG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
E1FXQ683ZR0G6S
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ディストリビューションを無効化
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront update-distribution \
>     --id ${DISTRIBUTION_ID} \
>     --distribution-config "${DELL_CONFIG}" \
>     --if-match ${ETAG} \
>     --region ${REGION} \
>     --no-cli-pager
{
    "ETag": "EVX7PAPE16URX",
    "Distribution": {
        "Id": "EIN33GD07JLDT",
        "ARN": "arn:aws:cloudfront::999999999999:distribution/EIN33GD07JLDT",
        "Status": "InProgress",
        "LastModifiedTime": "2024-08-04T11:54:36.649000+00:00",
        "InProgressInvalidationBatches": 0,
        "DomainName": "d18sbbratjvl6c.cloudfront.net",
        "ActiveTrustedSigners": {
            "Enabled": false,
            "Quantity": 0
        },
        "ActiveTrustedKeyGroups": {
            "Enabled": false,
            "Quantity": 0
        },
        "DistributionConfig": {
            "CallerReference": "cli-1722767554-44223",
            "Aliases": {
                "Quantity": 0
            },
            "DefaultRootObject": "index.html",
            "Origins": {
                "Quantity": 2,
                "Items": [
                    {
                        "Id": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                        "DomainName": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "S3OriginConfig": {
                            "OriginAccessIdentity": ""
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": "E2G9MJEEXTOJC1"
                    },
                    {
                        "Id": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                        "DomainName": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                        "OriginPath": "",
                        "CustomHeaders": {
                            "Quantity": 0
                        },
                        "CustomOriginConfig": {
                            "HTTPPort": 80,
                            "HTTPSPort": 443,
                            "OriginProtocolPolicy": "https-only",
                            "OriginSslProtocols": {
                                "Quantity": 1,
                                "Items": [
                                    "TLSv1.2"
                                ]
                            },
                            "OriginReadTimeout": 30,
                            "OriginKeepaliveTimeout": 5
                        },
                        "ConnectionAttempts": 3,
                        "ConnectionTimeout": 10,
                        "OriginShield": {
                            "Enabled": false
                        },
                        "OriginAccessControlId": ""
                    }
                ]
            },
            "OriginGroups": {
                "Quantity": 0
            },
            "DefaultCacheBehavior": {
                "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                "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": true,
                "LambdaFunctionAssociations": {
                    "Quantity": 0
                },
                "FunctionAssociations": {
                    "Quantity": 0
                },
                "FieldLevelEncryptionId": "",
                "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
            },
            "CacheBehaviors": {
                "Quantity": 2,
                "Items": [
                    {
                        "PathPattern": "/static/*",
                        "TargetOriginId": "20240804-handson-sincere-networker.s3.us-east-1.amazonaws.com-1722767554-972934",
                        "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": true,
                        "LambdaFunctionAssociations": {
                            "Quantity": 0
                        },
                        "FunctionAssociations": {
                            "Quantity": 0
                        },
                        "FieldLevelEncryptionId": "",
                        "CachePolicyId": "fe0144f2-7815-4b78-9544-cc88b1e0fedf"
                    },
                    {
                        "PathPattern": "/api",
                        "TargetOriginId": "4ad63asxjb.execute-api.us-east-1.amazonaws.com",
                        "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": true,
                        "LambdaFunctionAssociations": {
                            "Quantity": 0
                        },
                        "FunctionAssociations": {
                            "Quantity": 0
                        },
                        "FieldLevelEncryptionId": "",
                        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
                        "OriginRequestPolicyId": "8f0c7698-7ec2-42b7-9155-f1e2bc9418d0"
                    }
                ]
            },
            "CustomErrorResponses": {
                "Quantity": 0
            },
            "Comment": "",
            "Logging": {
                "Enabled": false,
                "IncludeCookies": false,
                "Bucket": "",
                "Prefix": ""
            },
            "PriceClass": "PriceClass_All",
            "Enabled": false,
            "ViewerCertificate": {
                "CloudFrontDefaultCertificate": true,
                "SSLSupportMethod": "vip",
                "MinimumProtocolVersion": "TLSv1",
                "CertificateSource": "cloudfront"
            },
            "Restrictions": {
                "GeoRestriction": {
                    "RestrictionType": "none",
                    "Quantity": 0
                }
            },
            "WebACLId": "arn:aws:wafv2:us-east-1:999999999999:global/webacl/handson-waf/a471ff68-5aba-411d-b2af-7eb66f520b04",
            "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 delete-distribution \
    --id ${DISTRIBUTION_ID} \
    --if-match ${ETAG} \
    --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ETagを取得
[cloudshell-user@ip-10-134-11-244 ~]$ ETAG=$(
>     aws cloudfront get-distribution-config \
>         --id ${DISTRIBUTION_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
EVX7PAPE16URX
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # ディストリビューションを削除
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront delete-distribution \
>     --id ${DISTRIBUTION_ID} \
>     --if-match ${ETAG} \
>     --region ${REGION}
```
### オリジンアクセス削除
```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} \
    --region ${REGION}

```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ETagを取得
[cloudshell-user@ip-10-134-11-244 ~]$ ETAG=$(
>     aws cloudfront get-origin-access-control \
>         --id ${ORIGIN_ACCESS_CONTROL_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
ETVPDKIKX0DER
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront delete-origin-access-control \
>     --id ${ORIGIN_ACCESS_CONTROL_ID} \
>     --if-match ${ETAG} \
>     --region ${REGION}
```
### キャッシュポリシー削除
```bash:コマンド
# ETagを取得
ETAG=$(
    aws cloudfront get-cache-policy \
        --id ${CACHEPOLICY_ID} \
        --query ETag \
        --output text
) \
&& echo ${ETAG}

# キャッシュポリシー削除
aws cloudfront delete-cache-policy \
    --id ${CACHEPOLICY_ID} \
    --if-match  ${ETAG}\
    --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ETagを取得
[cloudshell-user@ip-10-134-11-244 ~]$ ETAG=$(
>     aws cloudfront get-cache-policy \
>         --id ${CACHEPOLICY_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
E23ZP02F085DFQ
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # キャッシュポリシー削除
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront delete-cache-policy \
>     --id ${CACHEPOLICY_ID} \
>     --if-match  ${ETAG}\
>     --region ${REGION}
```
### オリジンリクエストポリシー削除
```bash:コマンド
# ETagを取得
ETAG=$(
    aws cloudfront get-origin-request-policy \
        --id ${ORIGIN_REQUESTPOLICY_ID} \
        --query ETag \
        --output text
) \
&& echo ${ETAG}

# オリジンリクエストポリシー削除
aws cloudfront delete-origin-request-policy \
    --id ${ORIGIN_REQUESTPOLICY_ID} \
    --if-match  ${ETAG}\
    --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ETagを取得
[cloudshell-user@ip-10-134-11-244 ~]$ ETAG=$(
>     aws cloudfront get-origin-request-policy \
>         --id ${ORIGIN_REQUESTPOLICY_ID} \
>         --query ETag \
>         --output text
> ) \
> && echo ${ETAG}
E23ZP02F085DFQ
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # オリジンリクエストポリシー削除
[cloudshell-user@ip-10-134-11-244 ~]$ aws cloudfront delete-origin-request-policy \
>     --id ${ORIGIN_REQUESTPOLICY_ID} \
>     --if-match  ${ETAG}\
>     --region ${REGION}
```
## AWS WAFの削除
### Web ACL削除
```bash:コマンド
# 変数
WEB_ACL_NAME="handson-waf" \
&& echo ${WEB_ACL_NAME}

# lock-token取得
WAFV2_LOCKTOKEN=$(
    aws wafv2 get-web-acl \
        --name handson-waf \
        --scope CLOUDFRONT \
        --id ${WEB_ACL_ID} \
        --no-cli-pager \
        --region ${REGION} \
        --query LockToken \
        --output text
) \
&& echo ${WAFV2_LOCKTOKEN}

# Web ACL削除
aws wafv2 delete-web-acl \
    --name ${WEB_ACL_NAME} \
    --scope CLOUDFRONT \
    --id ${WEB_ACL_ID} \
    --lock-token ${WAFV2_LOCKTOKEN} \
    --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # 変数
[cloudshell-user@ip-10-134-11-244 ~]$ WEB_ACL_NAME="handson-waf" \
> && echo ${WEB_ACL_NAME}
handson-waf
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # lock-token取得
[cloudshell-user@ip-10-134-11-244 ~]$ WAFV2_LOCKTOKEN=$(
>     aws wafv2 get-web-acl \
>         --name handson-waf \
>         --scope CLOUDFRONT \
>         --id ${WEB_ACL_ID} \
>         --no-cli-pager \
>         --region ${REGION} \
>         --query LockToken \
>         --output text
> ) \
> && echo ${WAFV2_LOCKTOKEN}
e31659be-da5b-4393-bce2-256623335626
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # Web ACL削除
[cloudshell-user@ip-10-134-11-244 ~]$ aws wafv2 delete-web-acl \
>     --name ${WEB_ACL_NAME} \
>     --scope CLOUDFRONT \
>     --id ${WEB_ACL_ID} \
>     --lock-token ${WAFV2_LOCKTOKEN} \
>     --region ${REGION}
```
## Amazon API Gatewayの削除
```bash:コマンド
aws apigateway delete-rest-api \
    --rest-api-id ${RESET_API_ID} \
    --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ aws apigateway delete-rest-api \
>     --rest-api-id ${RESET_API_ID} \
>     --region ${REGION}
```
## AWS Lambdaの削除
```bash:コマンド
aws lambda delete-function \
    --function-name ${FUNCTION_NAME} \
    --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ aws lambda delete-function \
>     --function-name ${FUNCTION_NAME} \
>     --region ${REGION}
```
## S3バケットの削除
```bash:コマンド
# S3バケット内のすべてのオブジェクトを削除
aws s3 rm s3://${S3_BUCKET_NAME} \
    --recursive \
    --region ${REGION}

# S3バケットを削除
aws s3api delete-bucket \
    --bucket ${S3_BUCKET_NAME} \
    --region ${REGION}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # S3バケット内のすべてのオブジェクトを削除
[cloudshell-user@ip-10-134-11-244 ~]$ aws s3 rm s3://${S3_BUCKET_NAME} \
>     --recursive \
>     --region ${REGION}
delete: s3://20240804-handson-sincere-networker/static/js/script.js
delete: s3://20240804-handson-sincere-networker/static/image/cloudfront.png
delete: s3://20240804-handson-sincere-networker/static/css/styles.css
delete: s3://20240804-handson-sincere-networker/index.html
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # S3バケットを削除
[cloudshell-user@ip-10-134-11-244 ~]$ aws s3api delete-bucket \
>     --bucket ${S3_BUCKET_NAME} \
>     --region ${REGION}
```
## IAM
### IAMロール削除
```bash:コマンド
# ロールにアタッチされているポリシーをリスト
POLICIES=$(
    aws iam list-attached-role-policies \
        --role-name ${ROLE_NAME} \
        --query 'AttachedPolicies[*].PolicyArn' \
        --output text
) \
&& echo ${POLICIES}

# リスト内のポリシーをデタッチする
for POLICY in ${POLICIES}; do
    aws iam detach-role-policy \
        --role-name ${ROLE_NAME} \
        --policy-arn ${POLICY}
done

# IAMロールの削除
aws iam delete-role \
    --role-name ${ROLE_NAME}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # ロールにアタッチされているポリシーをリスト
[cloudshell-user@ip-10-134-11-244 ~]$ POLICIES=$(
>     aws iam list-attached-role-policies \
>         --role-name ${ROLE_NAME} \
>         --query 'AttachedPolicies[*].PolicyArn' \
>         --output text
> ) \
> && echo ${POLICIES}
arn:aws:iam::999999999999:policy/handson-lambda-policy arn:aws:iam::aws:policy/TranslateReadOnly
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # リスト内のポリシーをデタッチする
[cloudshell-user@ip-10-134-11-244 ~]$ for POLICY in ${POLICIES}; do
>     aws iam detach-role-policy \
>         --role-name ${ROLE_NAME} \
>         --policy-arn ${POLICY}
> done
[cloudshell-user@ip-10-134-11-244 ~]$ 
[cloudshell-user@ip-10-134-11-244 ~]$ # IAMロールの削除
[cloudshell-user@ip-10-134-11-244 ~]$ aws iam delete-role \
>     --role-name ${ROLE_NAME}
```
### IAMポリシー削除
```bash:コマンド
# IAMポリシーの削除
aws iam delete-policy \
    --policy-arn ${POLICY_ARN}
```
```bash:出力
[cloudshell-user@ip-10-134-11-244 ~]$ # IAMポリシーの削除
[cloudshell-user@ip-10-134-11-244 ~]$ aws iam delete-policy \
>     --policy-arn ${POLICY_ARN}
```