Implementing External Issuersを見ると証明書を発行するためにACME等を使わずに自分で実装できるらしいが何をすればいいかよくわからなかったので実装して確認した。
cloudflare/origin-ca-issuerを参考にしたのでこっちを読めば基本的には何をすればいいかはわかる。
どういう時にこれを実装するかというと例えば社内に証明書を管理しているAPIサーバーがあったとしてそこから証明書を取得するとか。
一部エスパーしている部分もあるが大まかにはこのような流れで動いている。

参考実装はryota-sakamoto/cert-manager-external-sampleでkubebuilderを使っている
実装するべき点は3つある
customissuer_controller.go#L58
yamlではユーザー名とかパスワードを指定してreconcileすればいいと思う。
(Secret を使うとかそこはよしなにやる)
apiVersion: cert-manager.k8s.sakamo.dev/v1
kind: CustomIssuer
metadata:
name: customissuer-sample
spec:
user: user
password: password
CertificateRequest をreconcileし下記の点を実装すると目的が達成できる
issuerRef が一致するかどうか #L53CertificateRequest の Status の Certificate が空かどうか #L61issuerRef で指定したIssuerのStatus等の確認 #78CertificateRequest の Status の更新 #91まず Certificate に issuerRef を指定してapplyする。
そうすると CertificateRequest と Secret が生成される。
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-certificate
spec:
secretName: example-com-tls
dnsNames:
- example.com
- www.example.com
duration: 2160h
renewBefore: 720h
issuerRef:
group: cert-manager.k8s.sakamo.dev
kind: CustomIssuer
name: customissuer-sample
$ kubectl get certificate
NAME READY SECRET AGE
example-certificate False example-com-tls 9s
$ kubectl get certificaterequest
NAME READY AGE
example-certificate-crbmv 11s
$ kubectl get secret
NAME TYPE DATA AGE
default-token-lhhdl kubernetes.io/service-account-token 3 14d
example-certificate-g6gn6 Opaque 1 17s
CertificateRequest には Certificate で指定した値やCSRが含まれる。
また、Secret の名前はannotationsから取得できる。
$ kubectl get certificaterequest/example-certificate-crbmv -o go-template="{{ .spec.request }}" | base64 --decode
-----BEGIN CERTIFICATE REQUEST-----
(snip)
-----END CERTIFICATE REQUEST-----
$ kubectl get certificaterequest/example-certificate-crbmv -o jsonpath="{.metadata.annotations.cert-manager\.io\/private-key-secret-name}"
example-certificate-g6gn6
Secret には秘密鍵の情報が含まれている。
$ kubectl describe secret/example-certificate-g6gn6
Name: example-certificate-g6gn6
Namespace: default
Labels: cert-manager.io/next-private-key=true
Annotations: <none>
Type: Opaque
Data
====
tls.key: 1708 bytes
Status の更新は cert-manager にutilがあるのでそれを使うだけでいい。certificate_request_controller.go#L91
import (
cmutil "github.com/jetstack/cert-manager/pkg/api/util"
)
cmutil.SetCertificateRequestCondition(cr, certmanager.CertificateRequestConditionReady, metav1.ConditionTrue, certmanager.CertificateRequestReasonIssued, "Certificate issued")
ここは要件によって実装は変わるが上記で取得できる値を使ってAPIを叩いたりする。
参考実装では tls.key を使ってオレオレ証明書を作成している。certificate_request_controller.go#L117
ここまで実装して CertificateRequest から証明書を発行したりすると READY は TRUE になり、TLS証明書の Secret が作成される。
これを Ingress 等で指定すると使うことができる。
$ kubectl get certificaterequest
NAME READY AGE
example-certificate-crbmv True 27m
$ kubectl get certificate
NAME READY SECRET AGE
example-certificate True example-com-tls 27m
$ kubectl get secret/example-com-tls
NAME TYPE DATA AGE
example-com-tls kubernetes.io/tls 2 46s
下記のようにアクセスすると証明書が発行できていることが確認できる。
