LoginSignup
4

More than 1 year has passed since last update.

posted at

updated at

Organization

S3 で ホスティングしたウェブサイトをSSL化し、かつ特定の IP のみに開示する方法

はじめに

この記事は2020年の RevComm アドベントカレンダー25日目の記事です。クリスマス当日ですね!

前日は @qii-purine さんの「pythonでのアーキテクチャを考える」でした。

今回は最後となりますが、S3 で ホスティングしたウェブサイトをSSL化し、かつ特定の IP のみに開示する方法について紹介します。

やりたいこと

aws 使っている会社で、自分の作ったサイト(例えばデモサイト)を社内で共有するとき、みなさまどのように共有しますか。

典型的なやり方だと EC2 や Fargate でフロントエンドのサーバを立てるのではないかと思います。また、複数の静的ウェブページであれば、サーバーレスも検討するのではないかと思います。

そんな中、A) 頻繁にアクセスしない、B) 静的ファイルでも良い といった場合、 S3でのホスティング はコスト的に有効です。

しかし A) 社内のVPN のみで共有したい、B) サイトを転送時に暗号化したい と言う条件が加わると、SSL化特定のIPのみに開示 する必要があります。そのためには SSL 証明書発行 と ファイヤーウォール を用意する必要があります。

今回 Route 53, WAF, CloudFront, Certificate Manager, S3 を使って, どのようにSSL化して S3 でホスティングするかを紹介します。

また、今回 CloudFront を使いますが、CloudFront の場合はデータがキャッシュされるため、TTL (Time to Live) を意図的に設定しない限り変更が即時反映されません。TTL を短くすればいい話ですが、今回 S3 にあるサイトを変更したときにどのようにサイトを更新し、変更を即反映させるかについて紹介します。

( 内容はこちらのリンクとほぼ被りますので、もし、本記事でわからないことがあればそちらを読んでいただけると幸いです)

全体構成

全体構成はこんな感じです。

diagram.png

作成手順

取り組む前の準備

  • Route 53 でメインドメインをまだ作成していない場合は作成してください。
  • Route 53 に追加するレコード名を予め、検討してください。( revcomm-christmas-demo.example.com とします。)

素材の準備

まず、画像を用意します。(頑張ってコピー等でダウンロードしてください。)

christmas_tree.png

コードの準備

index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>Merry Christmas</title>
    <link rel='stylesheet' type='text/css' media='screen' href='main.css'>
</head>
<body>
    <div class="content">
        <img class="tree" src="./christmas_tree.png">
    </div>
</body>
</html>
main.css
.content{
    text-align:center;
    position: relative;
    width: 100%;
    height: 100%;
}

.content .text{
    position: absolute;
    text-align:center;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-family: 'Charm', cursive;
    font-size: 5em; 
}

html {
    width: 100%;
    height: 100%;
}

body{
    width: 100%;
    height: 100%;
    background: radial-gradient(#ffffff 50%, #91bee5 100%);
}


.ball{
    position: absolute;
    padding: 0px;
    margin: 0px;
    width: 20px;
    height: 20px;
    border-radius: 10px;
    background-color: rgb(218, 233, 247);
}

S3 の設定

S3 にアクセスし、バケットを新規作成してください。(revcomm-christmas-demo にします)

s00.png
s01.png

次にコンテンツをアップロードしてください。(ドラッグアンドドロップで可能)

s03.png

これで S3 にコンテンツが追加されました。

Certificate Manager の設定

SSL 証明書の作成です。
Certificate Manager にアクセスし、Region を N.Virginia にした状態で SSL 証明書の新規作成をクリックしてください。

image.png

予め検討した URL を入力してください。

image.png

DNS検証 にしてください。

image.png

レコード作成を選択してください。

image.png

レコードを追加すると、 Route 53 に SSL 証明書用のレコードが追加されます。

CloudFront の設定

CloudFront にアクセスし、CloudFront Distribution の新規作成をクリックしてください。

image.png

以下のようにパラメータを修正してください。(英語のままですが、ご容赦願います。)

  • Enable Origin Shield: No
  • Restrict Bucket Access: Yes
  • Origin Access Identity: Create New Identity
  • Generate Read Permissions on Bucket: Yes
  • Viewer Protocol Policy: Redirect
  • Price class: Use All Edge
  • Default Root Object: index.html
  • Alternate Domain Names: 予め検討した URL (revcomm-christmas-demo.example.com)
  • SSL Certificate: Custom SSL Certificate
  • Custom SSL: 予め検討した URL をタイプしてみてください。対応する SSL が出ます。(revcomm-christmas-demo と書けば出るはず)

cf01.png
cf02.png

しばらくすると、デプロイが完了します。(15分以上かかる可能性あり)
完了したら、 CloudFront のドメイン名をメモってください。

cf03.png

補足

  • S3 のポリシーも自動的に更新します。
  • OAI (Origin Access Identity) を使用することで、 S3 をpublic化をしない状態でホスティングすることができます。

Route 53 のレコード作成

Route 53 にアクセスし、ドメイン名 > レコードを追加 をクリックしてください。

image.png

レコードを作成してください。
Route ポリシーを Simple Route、 レコード名を予め検討した URL のサブドメイン名(revcomm-christmas-demo)、 レコードタイプをCNAME、 Value を先ほどメモった CloudFront を URL 入力してください。

image.png

WAF の設定

WAF にアクセスし、IP Sets で Region を Global (CloudFront) にした状態で新規 IP Set を作成してください。

image.png

IP を設定してください。

image.png

次にファイヤウィールの設定です。Web ACLs (Access Control List) で Region を Global (CloudFront) にした状態で 新規 ACL を作成してください。

image.png

任意の名前を設定して、関連リースの追加をクリックしてください。

image.png

WAF に関連するリソースを追加してください。(CloudFrontのID番号が表示する)

image.png

次へをクリックし、Add rules > Add my own rules ... をクリックしてください。

image.png

ルールタイプ IP Set を選択し、 ルール名(任意)を好きな名前にした状態で先ほど作成した IP set を入力し、作成してください。Default Action を Allow にしてください。

image.png

デフォルトを Block にしてください。

image.png

あとは ACL を作成して完成です。

結果

予め検討した URL (revcomm-christmas-demo.example.com) にアクセスすると、以下のようになります。

f00.png

ちなみに IP アドレスを変えると、以下のようになります。

f01.png

更新手順

次に更新方法です。

コードの修正

以下のようにコードを修正してください。

index.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8'>
        <title>Merry Christmas</title>
        <link rel='stylesheet' type='text/css' media='screen' href='main.css'>
        <link rel="preconnect" href="https://fonts.gstatic.com">
        <link href="https://fonts.googleapis.com/css2?family=Charm:wght@700&family=Pacifico&display=swap" rel="stylesheet">
    </head>
    <body>
        <div class="content">
            <img class="tree" src="./christmas_tree.png">
            <div class="text">
                We wish you a Merry Christmas <br />
                and a Happy New Year
            </div>
        </div>
    </body>

    <script>
        function drop_snow(){

            var snow_ball = document.createElement("div")
            snow_ball.className = "ball"
            snow_ball.style.top = 0 + 'px'
            snow_ball.style.left = Math.random() * document.body.clientWidth  + 'px'

            var content = document.getElementsByClassName('content')[0]
            content.appendChild(snow_ball);

            var pos = 0
            var refreshIntervalId = setInterval(frame, 10);

            function frame() {
                if (pos > document.body.clientHeight) {
                    content.removeChild(snow_ball);
                    clearInterval(refreshIntervalId);
                } else {
                    pos+= 1;
                    snow_ball.style.top = pos + 'px';
                    snow_ball.style.opacity = (1 - pos/document.body.clientHeight)
                }
            }
        }

        for (let i=0; i < 10; i ++){
            drop_snow()
        }
        setInterval(drop_snow, 500);
    </script>

</html>
main.css
.content{
    text-align:center;
    position: relative;
    width: 100%;
    height: 100%;
}

.content .text{
    position: absolute;
    text-align:center;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-family: 'Charm', cursive;
    font-size: 5em; 
}

html {
    width: 100%;
    height: 100%;
}

body{
    width: 100%;
    height: 100%;
    background: radial-gradient(#ffffff 50%, #91bee5 100%);
}


.ball{
    position: absolute;
    padding: 0px;
    margin: 0px;
    width: 20px;
    height: 20px;
    border-radius: 10px;
    background-color: rgb(218, 233, 247);
}

S3に再度アップロード

再度作成した S3 バケットにアップロードしてください。

CloudFront のキャッシュ無効化

CloudFront を通して一度サイトにアクセスすると、作成したウェブページがキャッシュされます。
そこで、キャッシュを無効化する必要があります。キャッシュを無効化するためにはまず CloudFront にアクセスし、作成した CloudFront Distribution をクリックしてください。

cf10.png

Invalidations で 無効化の作成 をクリックしてください。

cf11.png

あとは index.html 入力し、無効化を実行してください。

結果、こんな感じになります。(codepen です。画像だとつまらないので。)

See the Pen aws_s3_ssl_example1 by zomaphone1 (@zomaphone) on CodePen.

まとめ

以上で、S3 で ホスティングしたウェブサイトをSSL化し、かつ特定の IP のみに開示する方法について一つ紹介しました。

通常のホスティングであれば S3 で設定が済みますが、SSL化 と 特定の IP に対して公開したい場合、上記の手段は有効です。

もちろん他の手段として、S3 だけで解決する手段もあります。

こちらの記事のようにアクセスポイントを変えるだけ https で公開することもできます。IP と https のみを許容する場合は bucket policy を変えるだけで済みます。

Before:
https://revcomm-christmas-demo.s3-website-ap-northeast-1.amazonaws.com/
After: 
https://s3-ap-northeast-1.amazonaws.com/revcomm-christmas-demo/index.html

ただし、このやり方で注意していただきたいのが、httpsindex.html を明示的に示さないといけないことです。そのため、共有するときに URL の扱いに注意しないといけなくなります。

もし、リダイレクト等も含めたい、index.html まで記述させたくない場合、ぜひこちらの記事を参考に実施していただけると幸いです。

最後に

いかがでしたでしょうか。

今回の Qiita advent calendar は RevComm として初の試みではありましたが、有益な情報は得られましたでしょうか。

RevComm では「コミュニケーションを再発明し、人が人を想う社会を創る」というミッションを基に、電話営業をディープラーニングの技術で支援するプロダクト( Miitel ) をはじめ、コミュニケーションに関わる様々なプロダクト開発を行っており、日頃からコミュニケーションの在り方を再定義するという難しい課題に取り組んでいます。

弊社ではテックに関わらず成長に貪欲な人がたくさんいます。会社としてまだまだ若いところもありますが、新しい技術等に積極的に取り入れる会社ではあるので、エンジニアとしてテックスタックを広げたいという人にとってはいい会社です。

もし、弊社で一緒に働きたいという想いがあれば、あるいは少しでも興味があればぜひぜひ弊社の採用ページに応募してみてください。

ちなみに働き方について興味があれば、ぜひ CTO が書いたこちらの記事を読んでください。

では良いクリスマスを!!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4