OpenShift を素の状態で使い始めると、API サーバや Ingress には OpenShift 内部の仕組みで発行された証明書が使われます。これでもクラスタ内部では問題ありませんが、外部クライアントから素直に信頼される証明書に置き換えたい場面は多くあります。この記事では、OpenShift 4.21.8 に cert-manager を導入し、Cloudflare の DNS01 challenge を使って Let’s Encrypt から証明書を発行し、それを API 用と Ingress 用に適用する流れをまとめます。
今回の構成では Cloudflare を DNS に使います。cert-manager の Cloudflare 連携では API Token を使う方法が案内されており、Let’s Encrypt のワイルドカード証明書も DNS01 で扱う前提です。
OpenShift 上で使う cert-manager は、Red Hat が提供する cert-manager Operator for Red Hat OpenShift を使います。この Operator は OpenShift に最初から入っているわけではないため、Web コンソールからインストールします。また、コミュニティ版の cert-manager Operator を併用しないようにする必要があります。
前提
今回の前提は次のとおりです。
- DNS は Cloudflare
- OpenShiftのドメインは
o.chiroito.dev
- OpenShiftのドメインは
- OpenShift 4.21.8
YAMLの中にあるドメイン名やトークン、メールアドレスは適宜変更してください。
cert-manager Operator の導入
最初に OpenShift の Web コンソールから cert-manager Operator for Red Hat OpenShift をインストールします。手順としては、Web コンソールに cluster-admin 権限でログインし、Operator のカタログから該当の Operator を選んでインストールします。今回の構成では複数 namespace で Certificate を扱うため、インストールモードは AllNamespaces を選んでおくのが無難です。
ここはこの記事の本題ではないので詳細な画面操作までは追いませんが、少なくとも次の状態になっていれば先へ進めます。
- cert-manager Operator がインストール済み
cert-managernamespace に関連 Pod が起動している
Cloudflare の API Token を作成する
Cloudflare 側では cert-manager が DNS レコードを書き換えられるように API Token を作成します。
Cloudflare の画面では、Profile から API Tokens に進み、Create Token を選択します。Edit zone DNS のテンプレートを使ってもよいですし、Create Custom Token から自分で設定しても構いません。必要なのは次の 2 権限と 1 つの Zone Resources 設定です。
権限
Zone - DNS - EditZone - Zone - Read
Zone Resources
Include - All Zones
作成後に表示されるトークンはその場で控えておきます。
Cloudflare の認証情報を Secret として作成する
次に Cloudflare の API Token を Secret として登録します。ここで使う Secret は、後で ClusterIssuer の apiTokenSecretRef から参照されます。
apiVersion: v1 kind: Secret metadata: name: cloudflare-api-token-secret namespace : cert-manager type: Opaque stringData: api-token: <API Token>
Let’s Encrypt 用の ClusterIssuer を作成する
続いて ACME の発行元を定義します。今回の YAML では、ステージング用の example-issuer と本番用の prod-issuer を分けています。privateKeySecretRef は ACME アカウント鍵を保存するための Secret 名で、cert-manager が自動生成して管理します。
まずは Let’s Encrypt のステージング環境です。
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: example-issuer spec: acme: email: <メールアドレス> privateKeySecretRef: name: example-issuer-account-key server: 'https://acme-staging-v02.api.letsencrypt.org/directory' solvers: - dns01: cloudflare: apiTokenSecretRef: key: api-token name: cloudflare-api-token-secret
次に本番環境です。
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: prod-issuer spec: acme: email: <メールアドレス> privateKeySecretRef: name: prod-issuer-account-key server: 'https://acme-v02.api.letsencrypt.org/directory' solvers: - dns01: cloudflare: apiTokenSecretRef: key: api-token name: cloudflare-api-token-secret
ClusterIssuer を使っているのは、openshift-config と openshift-ingress の両方から同じ発行元を参照したいためです。cert-manager の Certificate は、issuerRef.kind を ClusterIssuer にすると cluster-scoped な発行元を参照できます。
最初はステージング側で疎通確認をし、問題がなければ prod-issuer を使います。
Certificate を作成する
OpenShift の API 用証明書と Ingress 用証明書をそれぞれ Certificate として定義します。spec.secretName は cert-manager が自動作成して管理する Secret 名です。Certificate が属する namespace にその Secret が作られるため、API 用は openshift-config、Ingress 用は openshift-ingress に作ります。
まずは API 用です。
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: api-tls-cert namespace: openshift-config spec: commonName: api.o.chiroito.dev dnsNames: - api.o.chiroito.dev isCA: false issuerRef: kind: ClusterIssuer name: prod-issuer secretName: api-secret
次に Ingress 用です。
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: ingress-tls-cert namespace: openshift-ingress spec: commonName: apps.o.chiroito.dev dnsNames: - apps.o.chiroito.dev - '*.apps.o.chiroito.dev' isCA: false issuerRef: kind: ClusterIssuer name: prod-issuer secretName: ingress-secret
Ingress 側で *.apps.o.chiroito.dev を入れているのは、OpenShift の Route が通常 アプリ名-namespace.apps... のようなホスト名で公開されるためです。
Certificate を作成したあとは、まず cert-manager 側で発行が成功しているかを確認します。
oc get certificate -A oc describe certificate api-tls-cert -n openshift-config oc describe certificate ingress-tls-cert -n openshift-ingress
Secret が生成されていることも確認します。
oc get secret api-secret -n openshift-config oc get secret ingress-secret -n openshift-ingress
OpenShift 側に Secret をひも付ける
証明書を発行しただけでは、まだ OpenShift の API サーバや Ingress はそれを使いません。最後に、cert-manager が作成した Secret を OpenShift 側の設定に参照させます。API サーバの named certificate は APIServer/cluster の spec.servingCerts.namedCertificates で設定し、Ingress の既定証明書は IngressController/default の spec.defaultCertificate.name で設定します。
API サーバ側は次のとおりです。
apiVersion: config.openshift.io/v1 kind: APIServer metadata: name: cluster spec: audit: profile: Default servingCerts: namedCertificates: - names: - api.o.chiroito.dev servingCertificate: name: api-secret
kube-apiserver のロールアウト状況を確認します。
oc get clusteroperators kube-apiserver oc get apiserver cluster -o yaml
Ingress 側は次の設定です。
apiVersion: operator.openshift.io/v1 kind: IngressController metadata: name: default namespace: openshift-ingress-operator spec: defaultCertificate: name: ingress-secret (略)
IngressController の defaultCertificate は openshift-ingress namespace にある Secret を参照します。Route 側で個別の証明書を指定していない場合、この既定証明書が使われます。OpenShift は既定では内部生成のワイルドカード証明書を使いますが、ここを差し替えることで外部から信頼される証明書に置き換えられます。
defaultCertificate の参照が反映されているかを確認します。
oc get ingresscontroller/default -n openshift-ingress-operator -o yaml
最後にクライアント側から証明書を確認します。API であれば https://api.o.chiroito.dev:6443、Ingress であればWebコンソールにブラウザで証明書チェーンを確認すると分かりやすいです。