Route53と連携したExternalDNSをhttps化する


## はじめに
以前、EKSにExternalDNS用のポッドを作成して、
指定のFQDNでサービスにアクセスする方法について記載しました。([前回記事](https://qiita.com/guile/items/d41399f579d1a62634c0))
今回は公開したサービスをhttps化してアクセスする方法について記載します。


## 前提
- AWSのリソースは[terraform](https://www.terraform.io/)を利用してデプロイします。
  - terraformバージョン: `v0.15.1`
- kubernetesはkubectlのcliを利用して操作します。
  - kubernetesバージョン: `1.19`
- EKSは作成済みとします。
- 本ページでは利用するドメインを`sample.com`とします。
- 前回記事の続きですので、ExternalDNSは構築済みとします。


## ACM証明書を作成
ACM証明書を作成し、ドメインに紐付けるため以下のリソースをデプロイします。

- [aws_acm_certificate](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate)
  ACM証明書です。
  DNS検証を利用するのが一般的です。
  DNS検証済みの証明書を要求し、必要な検証レコードを展開して検証が完了するのを待ちます。
  
- [aws_route53_record](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record)
  ホストゾーン内にCNAMEレコードを作成します。
  証明書発行時にドメインの所有を証明するために作成します。
  
- [aws_acm_certificate_validation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation)
  作ったACM証明書とCNAMEレコードの連携をします。

```
resource "aws_acm_certificate" "acm-certificate" {
  domain_name = "*.sample.com"
  validation_method = "DNS"

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_route53_record" "validation" {
  zone_id = aws_route53_zone.main.id
  ttl = 60

  name    = "${element(aws_acm_certificate.acm-certificate.domain_validation_options.*.resource_record_name, 0)}"
  type    = "${element(aws_acm_certificate.acm-certificate.domain_validation_options.*.resource_record_type, 0)}"
  records = [
      "${element(aws_acm_certificate.acm-certificate.domain_validation_options.*.resource_record_value, 0)}"
  ]

  depends_on = [
      aws_acm_certificate.acm-certificate
  ]
}

resource "aws_acm_certificate_validation" "acm-certificate-validation" {
  certificate_arn = aws_acm_certificate.acm-certificate.arn

  validation_record_fqdns = ["${element(aws_route53_record.validation.*.fqdn, 0)}"]
}
```

## Certificateの確認
デプロイ後、ACMにて検証が成功していることを確認する。
また、以下のようにKubernetesで利用可能なARNが記載されているので控えておく。

![acm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271464/8e90b8ea-6d26-213b-be51-08e885969bb6.png)



## サンプルアプリケーションのデプロイ
- sample_deployment.yml

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  selector:
    matchLabels:
      app: sample-app
  replicas: 2
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
      - name: nginx-container
        image: nginx:latest
        ports:
        - containerPort: 80
```

- sample_service.yml  
annotationsにcertificationのarn、ポート、プロトコルを以下のように指定する

```
apiVersion: v1
kind: Service
metadata:
  name: sample-service
  annotations:
    external-dns.alpha.kubernetes.io/hostname: test.sample.com
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: <certificateのarn>
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
spec:
  type: LoadBalancer
  selector:
    app: sample-app
  ports:
  - protocol: TCP
    port: 443
    targetPort: 80
```

以下コマンド実行してwebブラウザから
`http://test.sample.com`にアクセスできるか確認

```
kubectl apply -f sample_deployment.yml
kubectl apply -f sample_service.yml
```

以下のようなnginxのトップ画面が表示されていれば、設定完了です。

![nginx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271464/287770e7-04f7-e6e8-9dfd-bc6a292a33e3.png)


# 参考
- [TerraformでACM証明書を作成してみた](https://dev.classmethod.jp/articles/acm-cert-by-terraform/)
- [EKSのいーかんじなサービス公開方法](https://speakerdeck.com/sugimount/expose-service-eks-externaldns-acm?slide=25)