その辺にいるITインフラ屋さん

たまーに気が向いた時に適当な事を書く個人の日記みたいなもの。個人で作ったアプリのサポートページとしても利用しています。

KubernetesでAmbassadorを使ってhttps通信をさせる

過去の記事でGKEを使ってnginxを動かしてみましたが、httpsの通信は出来ない状態でした。nginx自体にLet's Encryptの証明書を設定してhttps通信をさせる事も出来ますが、nginx自体を自前で管理するのはしたくないです。AmbassadorというAPI Gatewayとして動作させるものがあるので利用してみました。



Ambassadorの設定をする

基本的にDeploying Ambassador to Kubernetesと同じです。下記はGKEで利用した場合の流れになります。

  • clusterrolebindingを設定する

    • kubectl create clusterrolebinding my-cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud info --format="value(config.account)")
  • ambassadorをローカルにダウンロードしてデプロイする

    • curl -O https://www.getambassador.io/yaml/ambassador/ambassador-rbac.yaml
    • kubectl apply -f ambassador-rbac.yaml
  • ambassadorのServiceを作成する
    • ambassador-service.yamlを作成する
    • kubectl apply -f ambassador-service.yamlでデプロイする
# ambassador-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: ambassador
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  ports:
   - port: 80
     targetPort: 8080
  selector:
    service: ambassador
  • nginxのdeploymentを起動させる (過去の記事参考)
  • nginxのserviceにAmbassadorのannotationsを追加する
apiVersion: v1
kind: Service
metadata:
  name: nginx
  annotations:
    getambassador.io/config: |
      ---
      apiVersion: ambassador/v1
      kind:  Mapping
      name:  nginx_mapping
      prefix: /nginx/
      service: nginx
spec:
  selector:
    name: nginx
  ports:
  - port: 80
    name: http-nginx
    targetPort: http-nginx-port
  • kubectl get svc ambassador で EXTERNAL-IPを確認する
mayu-mbp-2:kubernetes mayu$ kubectl get svc ambassador
NAME         TYPE           CLUSTER-IP   EXTERNAL-IP    PORT(S)                      AGE
ambassador   LoadBalancer   *****         *****     80:30294/TCP,443:32689/TCP   178m
  • <EXTERNAL-IP>/nginx/にブラウザで接続するとnginxの初期画面が表示される。 f:id:mayuki123:20190602174439p:plain

cert-managerを使って証明書を準備する

基本的にはcert-managerAmbassadorのドキュメントを参考にしています。cert-managerは Let's EncryptACMEプロトコルを利用して証明書を自動更新する事が出来ます。

事前準備

  • namespace cert-managerを作成する
    • kubectl create namespace cert-manager
  • resource validationの除外設定をしておきます。
  • kubectl label namespace cert-manager certmanager.k8s.io/disable-validation=true
  • cert-managerの設定をダウンロードしてデプロイします。
    • curl -O https://raw.githubusercontent.com/jetstack/cert-manager/release-0.7/deploy/manifests/cert-manager.yaml
    • kubectl apply -f cert-manager.yaml

証明書の作成

issuerCertificate リソースを作成する必要があります。Issuerはクライアント証明書でCertificateはサーバ証明書の発行を行います。ネームスペースに閉じた証明書を利用する場合は kind: Issuerクラスタ全体で利用する場合は kind: ClusterIssuerで作成をしてください。この記事ではClusterIssuerで進めます。

  • ClusterIssuer リソースを作成する
    • kubectl apply -f clusterIssuer.yaml
# clusterIssuer.yaml
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: <mail-address>
    privateKeySecretRef:
      name: letsencrypt-staging
    http01: {}
  • Certificateリソースを作成する
    • kubectl apply -f certificate.yaml
# certificate.yaml
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: kubernetes-certificate
  namespace: default
spec:
  secretName: kubernetes-cert-secret
  issuerRef:
    name: letsencrypt-staging
    kind: ClusterIssuer
  dnsNames:
  - <your_domain>
  acme:
    config:
    - http01:
        ingressClass: nginx
      domains:
      - <your_domain>

HTTP-01 Challengeの設定

ACME認証では HTTPかDNSを利用するかの二種類があります。
(Ambassadorのドキュメント)

  • cert-managerのpodから acme-http-domainacme-http-tokenを取得する
    • kubectl logs cert-manager-69568fb89d-76zm6 -n cert-manager | grep acme-http
    • 下記のようなログが出力されます
I0608 21:19:28.249101       1 ingress.go:49] 
Looking up Ingresses for selector certmanager.k8s.io/acme-http-domain=161156668,certmanager.k8s.io/acme-http-token=1100680922
  • acme-challenge-service リソースを作成します。
    • 先ほど取得したacme-http-domainacme-http-tokenを書き換えます。
apiVersion: v1
kind: Service
metadata:
  name: acme-challenge-service
  annotations:
    getambassador.io/config: |
      ---
      apiVersion: ambassador/v1
      kind: Mapping
      name: acme-challenge-mapping
      prefix: /.well-known/acme-challenge
      rewrite: ""
      service: acme-challenge-service
spec:
  ports:
  - port: 80
    targetPort: 8089
  selector:
    certmanager.k8s.io/acme-http-domain: "161156668"  #rewrite
    certmanager.k8s.io/acme-http-token: "1100680922"  #rewrite

nginxにhttpsで通信出来てるかの確認

  • kubectl get svc ambassador で EXTERNAL-IPを確認して設定したドメインに登録する
  • <ドメイン名>/nginx/にブラウザで接続するとhttps通信がされるようになりました。
    • httpで接続した際はhttpsにリダイレクトされます。

f:id:mayuki123:20190609064026p:plain


一通りやってみましたが、実施すべき事が多いですね。 消したり作ったりする場合は、クラスタ構築のパイプラインを作った方が良さそう。