ブログをSSL化した
Table of Contents
やらなきゃなーと思っていたこのブログのSSL化をようやくやった。 S3の静的ウェブサイトホスティングだったので、 ACMで証明書を発行してそれを使ってCloudFrontを通して配信している。
つまづきポイントは以下の3点。
証明書はus-east-1
リージョンで作る必要がある #
terraformのproviderにap-northeast-1
を指定していたのでそこに作られてしまった。
terraform module内に専用のproviderを定義して、
aws_acm_certificate
にprovider
を指定した。
Alternate Domain Namesの指定が必要 #
ChromeではERR_SSL_VERSION_OR_CIPHER_MISMATCH
というエラーになる。
opensslコマンドで接続した場合は以下のような出力に。
$ openssl s_client -connect blog.handlena.me:443 -servername blog.handlena.me -debug
CONNECTED(00000006)
write to 0x7f9ad8e02260 [0x7f9ada00e003] (225 bytes => 225 (0xE1))
0000 - 16 03 01 00 dc 01 00 00-d8 03 03 14 fa 46 ce b9 .............F..
0010 - 38 2c 98 b7 c3 ea 20 a5-27 3d 2e c0 59 fa 55 20 8,.... .'=..Y.U
0020 - 7a 54 47 37 0d b2 18 89-41 97 0e 00 00 60 cc a9 zTG7....A....`..
0030 - cc a8 cc aa c0 30 c0 2c-c0 28 c0 24 c0 14 c0 0a .....0.,.(.$....
0040 - 00 9f 00 6b 00 39 ff 85-00 c4 00 88 00 81 00 9d ...k.9..........
0050 - 00 3d 00 35 00 c0 00 84-c0 2f c0 2b c0 27 c0 23 .=.5...../.+.'.#
0060 - c0 13 c0 09 00 9e 00 67-00 33 00 be 00 45 00 9c .......g.3...E..
0070 - 00 3c 00 2f 00 ba 00 41-c0 11 c0 07 00 05 00 04 .<./...A........
0080 - c0 12 c0 08 00 16 00 0a-00 15 00 09 00 ff 01 00 ................
0090 - 00 4f 00 00 00 15 00 13-00 00 10 62 6c 6f 67 2e .O.........blog.
00a0 - 68 61 6e 64 6c 65 6e 61-2e 6d 65 00 0b 00 02 01 handlena.me.....
00b0 - 00 00 0a 00 08 00 06 00-1d 00 17 00 18 00 23 00 ..............#.
00c0 - 00 00 0d 00 1c 00 1a 06-01 06 03 ef ef 05 01 05 ................
00d0 - 03 04 01 04 03 ee ee ed-ed 03 01 03 03 02 01 02 ................
00e0 - 03 .
read from 0x7f9ad8e02260 [0x7f9ada009e03] (5 bytes => 5 (0x5))
0000 - 15 03 03 00 02 .....
read from 0x7f9ad8e02260 [0x7f9ada009e08] (2 bytes => 2 (0x2))
0000 - 02 28 .(
4758201964:error:14004410:SSL routines:CONNECT_CR_SRVR_HELLO:sslv3 alert handshake failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.200.4/libressl-2.6/ssl/ssl_pkt.c:1205:SSL alert number 40
4758201964:error:140040E5:SSL routines:CONNECT_CR_SRVR_HELLO:ssl handshake failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.200.4/libressl-2.6/ssl/ssl_pkt.c:585:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 0 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
Start Time: 1545553898
Timeout : 7200 (sec)
Verify return code: 0 (ok)
---
tfファイルではaws_cloudfront_distribution
にaliases
を指定すればいい。
/foo/bar/
で/foo/bar/index.html
を表示 #
S3から直接返していた場合はS3がindex.htmlを返してくれていた。
CloudFront経由かつoriginにS3バケット(BUCKET_NAME.s3.amazonaws.com
)を指定した場合はこれが働かない。
S3の静的ウェブサイトホスティングが提供しているURL(BUCKET_NAME.s3-website-REGION.amazonaws.com
)を指定すれば
S3が返すindex.htmlをCloudFrontがそのまま返してくれる。
静的ウェブサイトホスティングをそのまま残すことになるが、 対象のバケットには公開するためのファイルしか置いていないので問題ないだろう。
参考: CloudFront に S3 bucket のサブディレクトリパスのコンテンツを参照させる - Qiita
terraform moduleは以下の通り。
variables.tfは省略。
外からはdomain_name
の指定ができるだけ。
locals {
origin_id = "${lookup(var.website, "${terraform.workspace}.domain_name")}_origin"
}
provider "aws" {
version = "~> 1.25.0"
profile = "private"
region = "us-east-1"
alias = "us-east-1"
}
resource "aws_s3_bucket" "bucket" {
bucket = "${lookup(var.website, "${terraform.workspace}.domain_name")}"
acl = "private"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadForGetBucketObjects",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::${lookup(var.website, "${terraform.workspace}.domain_name")}/*"
}
]
}
EOF
website {
index_document = "index.html"
error_document = "404.html"
}
}
resource "aws_acm_certificate" "cert" {
provider = "aws.us-east-1"
domain_name = "${lookup(var.website, "${terraform.workspace}.domain_name")}"
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
}
resource "aws_cloudfront_distribution" "distribution" {
aliases = ["${lookup(var.website, "${terraform.workspace}.domain_name")}"]
origin {
domain_name = "${lookup(var.website, "${terraform.workspace}.domain_name")}.s3-website-ap-northeast-1.amazonaws.com"
origin_id = "${local.origin_id}"
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "http-only"
origin_ssl_protocols = ["TLSv1.1", "TLSv1.2"]
}
}
enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"
default_cache_behavior {
allowed_methods = ["HEAD", "GET"]
cached_methods = ["HEAD", "GET"]
target_origin_id = "${local.origin_id}"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
compress = true
viewer_protocol_policy = "redirect-to-https"
min_ttl = 0
max_ttl = 0
default_ttl = 0
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
acm_certificate_arn = "${aws_acm_certificate.cert.arn}"
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.1_2016"
}
}
前ふたつはAWSコンソールでポチポチしていれば気づいたはずだけど、 やる気を出して最初からtfファイルを書いてリソース作成したらデフォルト値になってしまっていた。
ほんとはDNS設定もここに書きたかったが、Route53管理ではないので手動設定。
.me
も取れるようにならないかな・・・。
これで心おきなく年が越せる。