これはAWS Certificate Manager (ACM)入門ハンズオン資料の一部です。
最初から続けて行っている場合「0.準備」の各項は作業不要です。第1項へ進んでください。
前提条件
us-east-1 リージョンにACMによるSSL証明書を発行済みであること。
(ALBは他リージョンでも利用可能ですが、今回はCloudFrontとSSL証明書を共有する事を想定しているため us-east-1 リージョンとしています)
us-east-1 リージョンにWebサーバが稼働しているEC2インスタンスが起動していること。
デフォルトVPCとサブネットが存在すること
us-east-1 リージョンにデフォルトVPCと、デフォルトVPCの各AZにサブネットが1つずつ存在すること。
アカウントを作成後、VPCに変更削除をしていなければ問題ありません。
必要な権限
トラブル防止の為、全ての操作が可能なクレデンシャル(アカウント)を原則として使用してください。
AWS CLI
以下のバージョンで動作確認済
- AWS CLI 1.10.63
aws --version
aws-cli/1.10.63 Python/2.7.11 Darwin/15.6.0 botocore/1.4.53
注意:elbv2は2016年8月実装の新機能です。バージョン 1.10.57 より古い場合は動作しません。
次のコマンドを実行して最新版に更新しましょう。
sudo -H pip install -U awscli
- 準備
=======
0.1. リージョンの決定
今回はバージニアリージョン(us-east-1)で作業してください。
export AWS_DEFAULT_REGION='us-east-1'
0.2. 変数の確認
プロファイルが想定のものになっていることを確認します。
aws configure list
Name Value Type Location
---- ----- ---- --------
profile <not set> None None
access_key ****************2LMA shared-credentials-file
secret_key ****************VXyK shared-credentials-file
region us-east-1 config-file ~/.aws/config
0.3. VPC IDの取得
VPC_ID=` aws ec2 describe-vpcs \
--filters Name=isDefault,Values=true \
--query 'Vpcs[].VpcId' \
--output text ` && echo ${VPC_ID}
vpc-xxxxxxxx
0.4. Subnet IDの取得
aws ec2 describe-subnets \
--query "Subnets[?VpcId==\`${VPC_ID}\`].[SubnetId,CidrBlock]" --output text
subnet-77777777 172.31.48.0/20
subnet-55555555 172.31.32.0/20
subnet-11111111 172.31.0.0/20
subnet-33333333 172.31.16.0/20
出力結果は左がsubnet id、右がそのサブネットのCIDRブロックです。
172.31.0.0/20のSubnet idを変数 SUBNET_ID1 へ、172.31.16.0/20のものをSUBNET_ID2 へ、コピーペーストして変数へ格納します。
SUBNET_ID1="subnet-11111111"
SUBNET_ID2="subnet-33333333"
0.5. ACM証明書arnの変数への格納
(本作業は最初から続けて行っている場合は不要です)
証明書のarnを変数 CERT_ARN へ格納します。
CERT_ARN=`aws acm list-certificates --region us-east-1 \
--query CertificateSummaryList[].CertificateArn \
--output text` && echo ${CERT_ARN}
arn:aws:acm:us-east-1:777777777777:certificate/9eb6865a-63a3-48df-92c2-ae113c877b33
0.6. EC2インスタンスIDの変数への格納
EC2_INSTANCE_ID=`aws ec2 describe-instances \
--query Reservations[].Instances[].InstanceId \
--output text` && echo ${EC2_INSTANCE_ID}
i-88888888888888888
- セキュリティグループの作成
=================
1.1. ALB用セキュリティグループの作成
セキュリティグループ elbv2-handson-sg を作成します。
SG_NAME="elbv2-handson-sg"
SG_ID=`aws ec2 create-security-group --group-name ${SG_NAME} \
--description ${SG_NAME} --output text` && echo ${SG_ID}
sg-59c3e63d
外部からのHTTPS接続をセキュリティグループに追加。
aws ec2 authorize-security-group-ingress --group-id ${SG_ID} --protocol 'tcp' --port 443 --cidr 0.0.0.0/0
返り値なし
- アプリケーションロードバランサの作成
=================
2.1. ロードバランサの作成
ELB_NAME="elbv2-handson-lb"
ELB_ARN=`aws elbv2 create-load-balancer --name ${ELB_NAME} \
--subnets ${SUBNET_ID1} ${SUBNET_ID2} --security-groups ${SG_ID} \
--query LoadBalancers[].LoadBalancerArn --output text `
aws elbv2 describe-load-balancers --load-balancer-arns ${ELB_ARN}
{
"LoadBalancers": [
{
"VpcId": "vpc-15b0ec70",
"LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:loadbalancer/app/elbv2-handson-lb/666a7169294ec5bc",
"State": {
"Code": "provisioning"
},
"DNSName": "elbv2-handson-lb-1654351783.ap-northeast-1.elb.amazonaws.com",
"SecurityGroups": [
"sg-c2a4b2a6"
],
"LoadBalancerName": "elbv2-handson-lb",
"CreatedTime": "2016-09-13T13:05:11.480Z",
"Scheme": "internet-facing",
"Type": "application",
"CanonicalHostedZoneId": "Z14GRHDCWA56QT",
"AvailabilityZones": [
{
"SubnetId": "subnet-67919410",
"ZoneName": "ap-northeast-1a"
},
{
"SubnetId": "subnet-692a7730",
"ZoneName": "ap-northeast-1c"
}
]
}
]
}
2.2. ターゲットグループの作成 (デフォルトアクション用)
デフォルトアクション(リスナへ届いた通常のアクセスの転送先)用のターゲットグループを作成します。
ELB_TG_NAME="elbv2-handson-tg"
ELB_TG_ARN=`aws elbv2 create-target-group --name ${ELB_TG_NAME} \
--protocol HTTP --port 80 --vpc-id ${VPC_ID} \
--query TargetGroups[].TargetGroupArn --output text `
aws elbv2 describe-target-groups --target-group-arns ${ELB_TG_ARN}
{
"TargetGroups": [
{
"HealthCheckPath": "/",
"HealthCheckIntervalSeconds": 30,
"VpcId": "vpc-15b0ec70",
"Protocol": "HTTP",
"HealthCheckTimeoutSeconds": 5,
"HealthCheckProtocol": "HTTP",
"LoadBalancerArns": [],
"UnhealthyThresholdCount": 2,
"HealthyThresholdCount": 5,
"TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/elbv2-handson-tg/0dc3bae28b0c8b99",
"Matcher": {
"HttpCode": "200"
},
"HealthCheckPort": "traffic-port",
"Port": 80,
"TargetGroupName": "elbv2-handson-tg"
}
]
}
2.3. ターゲットグループへターゲットを登録
ターゲット(Webサービスのインスタンス)をターゲットグループへ登録します。
インスタンスIDとポート番号の組み合わせで登録するので、コンテナインスタンスで複数のWebサービスコンテナが稼働していてもそれらを登録することができます。
ポート番号はターゲットグループのデフォルト値である場合、省略可能です。
aws elbv2 register-targets --target-group-arn ${ELB_TG_ARN} \
--targets Id=${EC2_INSTANCE_ID}
返り値なし
2.4. HTTPSリスナの作成
最後に外部からHTTPS(TCP/443)でアクセスを受け、ACMによるSSL証明書による処理を行い、ターゲットグループのWebサーバへHTTP(TCP/80)で接続するリスナを作成し、Webサーバへアクセスできるようにします。
ELB_LISTENER_ARN=`aws elbv2 create-listener --load-balancer-arn ${ELB_ARN} \
--protocol HTTPS --port 443 --certificates CertificateArn=${CERT_ARN} \
--default-actions Type=forward,TargetGroupArn=${ELB_TG_ARN} \
--query Listeners[].ListenerArn --output text `
aws elbv2 describe-listeners --listener-arns ${ELB_LISTENER_ARN}
{
"Listeners": [
{
"Protocol": "HTTPS",
"DefaultActions": [
{
"TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/hoge/e155d347d35f05f0",
"Type": "forward"
}
],
"SslPolicy": "ELBSecurityPolicy-2015-05",
"Certificates": [
{
"CertificateArn": "arn:aws:acm:ap-northeast-1:571972591141:certificate/07150260-d46a-4a5f-8f20-900a9573d0a6"
}
],
"LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:loadbalancer/app/hoge/b6183b688ccfbdce",
"Port": 443,
"ListenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:listener/app/hoge/b6183b688ccfbdce/c9dc5e52bde4de8e"
}
]
}
ここで3分ほど待ちます。
ロードバランサとターゲットが接続完了するのに時間がかかるからです。
2.5. ターゲットのヘルスチェック状況確認
aws elbv2 describe-target-health --target-group-arn ${ELB_TG_ARN}
{
"TargetHealthDescriptions": [
{
"HealthCheckPort": "80",
"Target": {
"Id": "i-5d3f2bc2",
"Port": 80
},
"TargetHealth": {
"State": "healthy"
}
}
]
}
State が healthy になっていることを確認します。
initial である場合はヘルスチェックが規定回数まで達していないので少し待って再実行します。
unhealthy など他の内容が表示された場合は、チューターか講師へ声を掛けてください。
2.6. DNSNameの取得
ALBはIPアドレスは動的で、DNS名をCNAMEまたはエイリアスレコードによって登録するためこの値を取得します。
DNSNAME=`aws elbv2 describe-load-balancers --load-balancer-arns ${ELB_ARN} \
--query LoadBalancers[].DNSName --output text `
echo ${DNSNAME}
elbv2-handson-lb-1654351783.ap-northeast-1.elb.amazonaws.com
- Route53の設定
=================
www.example.tk でアクセスできるようにするため、Route53の設定を行います。
今回はexample.tkでCloudFrontのS3コンテンツが、example.tkでALBによるEC2インスタンスのWebコンテンツが表示されるようにします。
3.1. Route53レコードセットの作成
まずRoute53へレコードを登録するためのJSONファイルを作成します。
cat << EOF > route53c.json
{
"Comment": "ALB-AliasRecord",
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"AliasTarget": {
"HostedZoneId": "Z35SXDOTRQ7X7K",
"EvaluateTargetHealth": false,
"DNSName": "${DNSNAME}."
},
"Type": "A",
"Name": "www.${DOMAINNAME}."
}
}
]
}
EOF
cat route53c.json
{
"Comment": "ALB-AliasRecord",
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"AliasTarget": {
"HostedZoneId": "Z35SXDOTRQ7X7K",
"EvaluateTargetHealth": false,
"DNSName": "elbv2-handson-lb-254473736.us-east-1.elb.amazonaws.com."
},
"Type": "A",
"Name": "www.example.tk."
}
}
]
}
HostedZoneIdに書かれている文字列は全ユーザ共通の固定値です。
ALBをエイリアスレコードに登録する場合は常にこの値を使用します。
JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。
jsonlint -q route53.json
返り値なし
3.2. Route53への登録
aws route53 change-resource-record-sets \
--hosted-zone-id ${HOSTED_ZONE_ID} --change-batch file://route53c.json
{
"ChangeInfo": {
"Status": "PENDING",
"Comment": "ALB-AliasRecord",
"SubmittedAt": "2016-10-13T08:34:57.794Z",
"Id": "/change/C3SSDTIES1RAMM"
}
}
- 動作確認
=================
4.1. Webブラウザでアクセス
echo https://www.${DOMAINNAME}/
https://www.example.tk/
WebブラウザでURLへアクセスしてみます。問題無く表示されたでしょうか。
Route53の機能であるエイリアスレコード機能によって、Zone APEXでも別名が利用できることがわかります。
4.2. HTTP/2対応の確認
これは外部のサイトで確認することができます。
https://tools.keycdn.com/http2-test
へアクセスして、URL欄に自分のサイトを入力してみましょう。
Yeah! www.example.tk supports HTTP/2.0.
緑色でこのような表示がされればHTTP/2対応です。
おめでとうございます。
ハンズオンの最終目標までこれで達成です。