GKEのIngressでLet's Encryptの証明書を利用できるようにする
はじめに
GKEのIngressでLet's Encryptの証明書を利用したかった、日本語のドキュメントを見つけたけど少し古く、CRDのAPIversionなど上がっており、一部設定項目などが変わっていたので、最新版での動作確認手順をまとめる
構成図
以下のような感じになる
参考資料
- 日本語の手順: https://www.namakedame.work/gke-cert-manager-cloud-dns-ingress/
- 新しめの手順説明1: https://kosyfrances.com/ingress-gce-letsencrypt/
- 新しめの手順説明2: https://kosyfrances.com/letsencrypt-dns01/
- 公式サイト: https://cert-manager.io/docs/
前提条件
- GCPのCloud DNSでドメインを管理している(hogehoge.comというドメインを管理してるとする)
- gcloud cliインストール/設定済み
- kubectlインストール/設定済み
- GKEのverは1.20以上
設定手順
cert-managerのデプロイ
2021/09時点で最新のv1.5.3を利用する
$ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.3/cert-manager.yaml
PodがReadyになればOK
$ kubectl get pods --namespace cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-848f547974-6hfgj 1/1 Running 0 29m
cert-manager-cainjector-54f4cc6b5-vsmsm 1/1 Running 0 29m
cert-manager-webhook-58fb868868-642kd 1/1 Running 0 29m
Cloud DNSの操作権限を持つGCPのIAM service accountを作成し、k8sからも参照できるようにする
利用するProjectIDを環境変数に持たせておく(別にやらなくても良い、記事用に)
$ export PROJECT_ID=xxxxxxxxx
GCPのService Account作成
$ gcloud iam service-accounts create dns01-solver
GCPのService Accountにdns admin権限を付与
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
--member serviceAccount:dns01-solver@$PROJECT_ID.iam.gserviceaccount.com \
--role roles/dns.admin
GCPのService Accountをjsonファイルにexport
$ gcloud iam service-accounts keys create service-account.json \
--iam-account dns01-solver@$PROJECT_ID.iam.gserviceaccount.com
GCPのService Accountのjsonファイルをk8sのsecretとして作成しておく (cert-managerが利用するため、cert-manager
namespaceに作成しておかないとエラーになるので注意)
$ kubectl create -n cert-manager secret generic clouddns-dns01-solver-svc-acct \
--from-file=service-account.json
Issuerの作成
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# 以下を変更すること
email: 発行者用のemail address
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- dns01:
cloudDNS:
# 以下を利用するGCPのプロジェクト名に変えること
project: $PROJECT_ID
serviceAccountSecretRef:
name: clouddns-dns01-solver-svc-acct
key: service-account.json
こちらをデプロイ
$ kubectl apply -f cluster-issuer.yml
Ready=Trueになるまで待つ
$ kubectl get clusterissuers.cert
NAME READY AGE
letsencrypt-prod True 3m
証明書発行(ワイルドカード証明書)
ワイルドカード証明書を発行します
*.hogehoge.com
という感じで、hogehoge.com
のサブドメイン全てに対して使える証明書になります(aaa.hogehoge.com
やbbb.hogehoge.com
などで使いまわせる)
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: hogehogecom
namespace: default
spec:
# 以下の名前でsecretが作られる
secretName: hogehogecom-tls
issuerRef:
# 1つ前の手順で作成した発行者を指定
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
# 以下を利用したいワイルドカード名にすること(これは前提の通り、GCPのCloud DNSで管理されていることが必須)
- "*.hogehoge.com"
$ kubectl apply -f certificate.yml
大体applyしてから0~5分程度で作成される
$ kubectl get certificate
NAME READY SECRET AGE
hogehogecom True hogehogecom-tls 24s
ずっとReadyがFalseの場合は下記を確認し、それぞれの詳細をdescribeで確認する。
certificateからchallengesが作られ、challengesからordersが作られている。
おそらくどこかでエラーが発生している
$ kubectl get orders
$ kubectl get challenges
Ingressで利用する静的外部IPを作成しておく
指定しない限りはIngress作り直すたびにLBのIP変わって、毎回CloudDNSの向き先を変えないといけないので、あらかじめLBに割り当てるIPを用意しておく
$ gcloud compute addresses create ingress-ip --global
ingressの場合はGlobalタイプじゃないとエラー出すので注意
HTTP(S) ロードバランサを作成する Ingress を使ってアプリケーションを公開する場合は、グローバル静的 IP アドレスを予約する必要があります。リージョン IP アドレスは Ingress では機能しません。
Ingreeで利用するホスト名の名前解決先を静的IPで指定しておく
今回利用するホスト(aaa.hogehoge.com とする)のAレコードを作成し、向き先を1つ前の手順で作成した静的外部IP(ingress-ip)のアドレスにしておく
Ingress/サンプルDeploymentを作成
適当にIngress用のアプリをデプロイします
(アプリ参考元-> https://matthewpalmer.net/kubernetes-app-developer/articles/kubernetes-ingress-guide-nginx-example.html )
kind: Pod
apiVersion: v1
metadata:
name: apple-app
labels:
app: apple
spec:
containers:
- name: apple-app
image: hashicorp/http-echo
args:
- "-text=apple"
---
kind: Service
apiVersion: v1
metadata:
name: apple-service
spec:
selector:
app: apple
ports:
- port: 5678
---
kind: Pod
apiVersion: v1
metadata:
name: banana-app
labels:
app: banana
spec:
containers:
- name: banana-app
image: hashicorp/http-echo
args:
- "-text=banana"
---
kind: Service
apiVersion: v1
metadata:
name: banana-service
spec:
selector:
app: banana
ports:
- port: 5678 # Default port for image
これらのserviceへのリクエストを制御するIngressをデプロイします
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
# 下記は前の手順で作成した静的外部IPのリソース名を指定する
kubernetes.io/ingress.global-static-ip-name: ingress-ip
# 作成したcluster-issuerのリソース名を指定
cert-manager.io/cluster-issuer: letsencrypt-prod
ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
# 今回利用するドメイン名を指定する
- aaa.hogehoge.com
# 証明書作成時に指定したsecret名を指定する
secretName: hogehogecom-tls
rules:
# 今回利用するドメイン名を指定する
- host: aaa.hogehoge.com
http:
paths:
- path: /apple
pathType: ImplementationSpecific
backend:
service:
name: apple-service
port:
number: 5678
- path: /banana
pathType: ImplementationSpecific
backend:
service:
name: banana-service
port:
number: 5678
コメントをつけた箇所が重要なポイントになります
動作確認
少し待って、ingressが作成されたら
へブラウザでアクセスしてみます。アドレスバーの横の南京錠アイコンがエラーを吐いてないと思います。
Discussion