リダイレクトサービス構築 AWS ALBパターン、Let’s Encryptパターン(複数の証明書付きネイキッドドメインを1台のサーバで管理)


AWS ALBパターン

  • 下記のようにLet’s Encryptを使用して1台で運用しているが、ALB使用ではマネジドサービスのメリットがあるので切り替え検討。
  • 説明や操作は参考サイトへ(お世話になっております)
  • デメリット
    • ドメインごとALB作成が必要 ・・・ 冗長化やLet’s Encryptの依存性とトレードオフか

ロードバランサー -> リストー -> ルールの表示/編集

参考


Let’s Encryptパターン

運用をシンプルにしたい

ネイキッドドメインをwwwのサブドメインにリダイレクトしたいが、証明書設定がないと止まる。
https://domain.com -> ブラウザが怒る(証明書警告) -> https://www.domain.com

wwwのサブドメインは証明書費用かけず運用中。

  • AWSのRoute53(CNAME) + Elastic Beanstalk + CloudFront + Certificate Manager

SSL必須の時代になり、証明書付きのネイキッドドメインのケースが増えてきた。
ネイキッドドメインのDNSレコードはIPしか指定できないため、とりあえず下記のようなセットで対応していた。

  • S3リダイレクト用バケット + CloudFront + Certificate Manager

EC2の一台に

サイトごと、二重の設定作業やコストが増えるので構成を変えてみた。
* リダイレクト用EC2(IP指定のため)
* サイトごとLet’s Encrypt設定(このくらいは我慢)

証明書はLet’s Encryptのwebrootオプションにする理由

  • ドメインオーナーではない(DNSレコード登録できない)
  • サーバ管理者である

/etc/httpd/conf.d/domain.com.conf

<VirtualHost *:80>
    ServerName domain.com
    DocumentRoot /var/www/html/domain.com
</VirtualHost>
<VirtualHost *:443>
    ServerName domain.com:443
    DocumentRoot /var/www/html/domain.com
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
    SSLCertificateFile /etc/letsencrypt/live/domain.com/cert.pem
    SSLCertificateKeyFile //etc/letsencrypt/live/domain.com/privkey.pem
    SSLCACertificateFile /etc/letsencrypt/live/domain.com/chain.pem
</VirtualHost>

/var/www/html/domain.com/index.html

<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
しばらくお待ちください。
</body>
</html>

/var/www/html/domain.com/.htaccess

RewriteCond %{REQUEST_URI} !(^/.well-known/) がないとwww.にリダイレクトされてしまうので発行に失敗する

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{SERVER_PORT} 80
  RewriteCond %{HTTP_HOST} !^www.
  RewriteCond %{REQUEST_URI} !(^/\.well-known/)
  RewriteRule ^(.*)$ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{SERVER_PORT} 443
  RewriteCond %{HTTP_HOST} !^www.
  RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>

やっと証明書発行

  • テストドメイン: domain.com
certbot-auto certonly --webroot -w /var/www/html/domain.com -d domain.com -m [email protected] --agree-tos

crontab -l

0 3 * * * /usr/bin/certbot-auto renew && /sbin/service httpd reload

メモ

  • テンプレートとする元ファイルから簡単追加

/var/www/html/default/.htaccess
/var/www/html/default/index.html

  • cmd
mkdir /var/www/html/{domain}

cp -aT /var/www/html/default /var/www/html/{domain}

監視

cronにより自動更新だが、たまに失敗するので監視は回しておく
サーバー証明書有効期限監視

参考

追記 証明書定期更新をhookで使用時

cron

10 3 * * * /etc/letsencrypt/renewal/aaa.bbb.info.sh

毎日更新をトライする

/etc/letsencrypt/renewal/aaa.bbb.info.sh

#!/bin/sh

certbot certonly \
  -d aaa.bbb.info \
  --email [email protected] \
  --agree-tos \
  --preferred-challenges dns \
  --keep-until-expiring \
  --text \
  --configurator certbot-external-auth:out \
  --certbot-external-auth:out-public-ip-logging-ok \
  --certbot-external-auth:out-handler /etc/letsencrypt/renewal-hooks/pre/aaa.bbb.info.sh

/sbin/service httpd restart
  • 期限内になると更新
  • --preferred-challenges dns にしたのでCNAME更新が必要
  • hookでRoute53レコードを更新

/etc/letsencrypt/renewal-hooks/pre/aaa.bbb.info.sh

#!/bin/sh

set -e
cmd="$1"
shift

ret=`aws sts assume-role --role-arn arn:aws:iam::xxxx427341:role/route53-register --role-session-name aws3-ec2`
export AWS_ACCESS_KEY_ID=`echo $ret | jq -r .Credentials.AccessKeyId`
export AWS_SECRET_ACCESS_KEY=`echo $ret | jq -r .Credentials.SecretAccessKey`
export AWS_SESSION_TOKEN=`echo $ret | jq -r .Credentials.SessionToken`

case "$cmd" in
    perform)
        HOSTED_ZONE_ID="/hostedzone/xxxx5NZ9H"
        FILENAME=`date "+%Y%m%d%H%M%S"`.json
        DIR=/var/log/letsencrypt/

        # 環境変数チェック
        if [ -z "$domain" ] || [ -z "$validation" ]; then
                echo "Undefined environment variable" 
                exit 1
        fi

        # 設定用jsonファイルを書き出し
        cat <<EOT > $DIR$FILENAME
{
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "_acme-challenge.$domain",
        "Type": "TXT",
        "TTL": 60,
        "ResourceRecords": [
          {
            "Value": "\"$validation\"" 
          }
        ]
      }
    }
  ]
}
EOT
        # jsonファイルをアップロードしてTXTレコードを追加
        aws route53 change-resource-record-sets --hosted-zone-id "$HOSTED_ZONE_ID" --change-batch file://$DIR$FILENAME

        # DNS反映待ち
        sleep 60
        ;;
    *)
        ;;
esac
  • STS(aws sts assume-role)で他アカウントのRoute53を参照できる