AWS EKSでLoadBalancerを使い、https通信する方法メモ

目的

  • EKSで公開したサービスをhttpsにしたい!

目次

httpsを行う核心部分

結論をさっさとみたい方はこちら

前提

  • ドメインを取得済み
    • 便宜上example5.comを持っているとします
    • Route53でのドメインが簡単
  • ドメインの証明書はAmazon Certificate Manager(ACM)を使ってる
    • 便宜上*.example5.comに対する証明書を持っているとします
    • ぽちぽちクリックするだけで取得可能

参考

EKSへのログイン方法

f:id:y-ni-shi:20200912151939p:plain クラスタをEKS作成している状態で、aws cliを使います

$ aws sts get-caller-identity

これで自分のawsアカウントにログインできている状態で(aws cliのセットアップは割愛)

$ aws eks --region ap-northeast-1 update-kubeconfig --name sample

EKSでnginxをデプロイします

  • deployment
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      app: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

確認

k8sクラスタからしかアクセスできないので、クラスタ内にbusyboxコンテナを立てて確認する f:id:y-ni-shi:20200912144627p:plain

まずはipアドレスを確認(EKSクラスタ内のプライベートなIPアドレス

kubectl get po -o=wide
NAME                        READY   STATUS    RESTARTS   AGE   IP             NODE                                             NOMINATED NODE   READINESS GATES
my-nginx-75897978cd-kxmhn   1/1     Running   0          96s   172.31.9.104   ip-172-31-7-95.ap-northeast-1.compute.internal   <none>           <none>
my-nginx-75897978cd-sxs6k   1/1     Running   0          96s   172.31.7.192   ip-172-31-7-95.ap-northeast-1.compute.internal   <none>           <none>

Podが2個たっていて、172.31.9.104172.31.7.192だということがわかる
busyboxをたてる

$ kubectl run --rm -it --image=busybox --restart=Never nginx-test sh

これでコンテナに入れるので、ここからwgetで確認する

/ # wget -O - 172.31.9.104
Connecting to 172.31.9.104 (172.31.9.104:80)
writing to stdout
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...略

無事にnginxのメッセージが帰ってきました

serviceをたてる

とりあえずはhttpで通信できるサービスをたてる

$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-nginx
  ports:
  - name: http
    port: 80
    targetPort: 80
  type: LoadBalancer
EOF
$ kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP                                                                    PORT(S)        AGE
kubernetes   ClusterIP      10.100.0.1     <none>                                                                         443/TCP        15m
my-service   LoadBalancer   10.100.4.181   a127d8af5450f4f43bfb21d5fe3a7800-1476400784.ap-northeast-1.elb.amazonaws.com   80:31724/TCP   5m17s

EC2のロードバランサをAWSのコンソールから確認
自動的にロードバランサが作られています
f:id:y-ni-shi:20200912161923p:plain

a127d8af5450f4f43bfb21d5fe3a7800-1476400784.ap-northeast-1.elb.amazonaws.comこれがELBのエンドポイント
この名前が伝搬するまでちょとっとかかりますので、watchしながらIPアドレスが帰ってくるまで待つ

$ watch nslookup a127d8af5450f4f43bfb21d5fe3a7800-1476400784.ap-northeast-1.elb.amazonaws.com

** server can't find hogehoge.ap-northeast-1.elb.amazonaws.com: NXDOMAINという表示ではなく、
こんなふうにレスポンスが来たら準備完了

Non-authoritative answer:
Name:   a127d8af5450f4f43bfb21d5fe3a7800-1476400784.ap-northeast-1.elb.amazonaws.com
Address: 52.196.124.185
Name:   a127d8af5450f4f43bfb21d5fe3a7800-1476400784.ap-northeast-1.elb.amazonaws.com
Address: 52.198.121.155
$ curl a127d8af5450f4f43bfb21d5fe3a7800-1476400784.ap-northeast-1.elb.amazonaws.com

さきほどのnginxと同じレスポンスがあるはず

名前をつける

Route53でルーティングをする 以下のように設定する

  • レコードセットを作成を選択する f:id:y-ni-shi:20200912155939p:plain

  • 名前をnginx.example5.comとして登録

  • エイリアスを「はい」
  • 先程作られたCLBを選択
  • [作成]をクリック f:id:y-ni-shi:20200912155944p:plain

確認する

しばらく待ってみると

$ curl nginx.example5.com

でnginxの返答がある

httpsにする

httpsにする

上記を参考に、serviceyamlを変更

$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012
spec:
  selector:
    app: my-nginx
  ports:
  - name: http
    port: 80
    targetPort: 80
  - name: https
    port: 443
    targetPort: 80
  type: LoadBalancer
EOF

このような感じになりました。

解説

  annotations:
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012

このannotationsの部分がキモのようで
この情報にあわせてLoadBalancerを作ってくれます

service.beta.kubernetes.io/aws-load-balancer-backend-protocol

  • バックエンド(今回の例でいうとnginx)がどのプロトコルで受けるか
    • 今回はこのLoadBalancerでTLSを終端して、nginxへはhttpでつなぎたいので、httpとしています

service.beta.kubernetes.io/aws-load-balancer-ssl-ports

  • ELBが何で受けるか、という指定
    • httpsで受ける指定

service.beta.kubernetes.io/aws-load-balancer-ssl-cert

  • ACMのarnを指定する
    • 指定した証明書を使ってTLS通信を行ってくれる

確認

$ curl nginx.example5.com

これでnginxのレスポンスがあればOK

まとめ

  • serviceanotationsで色々書くとLB設定に反映される