😃

cert-manager基礎知識

2022/01/16に公開

cert-managerとは

kubernetesクラスタ上でSSL/TLS証明書をシンプルに扱うためのツールです。
証明書の取得・更新・利用が簡単になります。

公式ドキュメント
https://cert-manager.io/docs/

この記事の内容

この記事では、cert-managerを利用していくにあたり、最低限おさえておきたい「証明書発行・利用の流れ」と、「登場人物」だけを簡単にまとめます。

証明書まわりは分かりづらいし、事故ったら大変なことになるので、あまり触りたくない箇所かもしれませんが、基礎知識を知っておくことで最初の足がかりになると思います。

cert-manager v1.6.1での話をしていきます。
また、Let's EncryptをIssuerとした流れを説明しますので、他のIssuer Typeでは内容が異なる箇所があります。

証明書発行・利用の簡単な流れ

まずざっくりとした流れを書いておきます。
実際のインストール方法や、操作などの詳細は公式ドキュメントに譲ります。

  1. cert-managerをインストールします。
  2. Issuerコンポーネントを作成します。
  3. Certificateコンポーネントを作成します。
  4. Issuer, Certificateコンポーネントの設定に応じて、指定した証明書発行者に対して指定したドメインの証明書要求が行われます。
  5. 指定されたドメインが、証明書要求者のコントロール下にあるか確認するため、証明書発行者はチャレンジを行います。
  6. チャレンジが完了したら、発行された証明書と鍵がSecretリソースに保存されます。
  7. Ingress等から証明書・鍵を保存したSecretを参照することで、証明書を利用した暗号通信が可能となります。

登場人物

cert-managerが証明書を取得・利用する際に、関わってくる登場人物を紹介します。

Issuer

https://cert-manager.io/docs/concepts/issuer/

  • 証明書発行者(CA: Certification Authority. 日本語では認証局)を表現しています。
    • 文字通り、証明書を発行する人です。
  • cert-managerにおいて、IssuerコンポーネントはCustom Resource Definition(CRD)で定義されるリソースです。
    • Issuerコンポーネントは同じnamespaceにしか、Certificateを発行できません。
      • 複数namespaceにまたがって発行したい場合はClusterIssuerコンポーネントを利用します。
  • エンドユーザーがmanifestファイルを作成し、管理します。

Certificate

https://cert-manager.io/docs/concepts/certificate/

  • X.509に基づいた証明書を表現しています。
    • こちらもCRDで定義されたKubernetes上のリソースです。
    • X.509は証明書の規格です。
  • エンドユーザーがmanifestファイルを作成し、管理します。

ACME Orders and Challenges

https://cert-manager.io/docs/concepts/acme-orders-challenges/

  • ACME(Automate Certificate Management Environment)
    • 自動で証明書を管理してくれる環境のことです。
    • Let’s Encryptが代表的なACME Issuerです。
  • 証明書署名要求を通すために、ACMEクライアント(つまりcert-managerであり、エンドユーザー)は指定したドメインを所有していることを、ACME Issuerに対して証明しなければならない。
    • これがACMEプロトコルにおけるチャレンジと呼ばれる仕組み。
    • このチャレンジを完了するために、cert-managerは以下の2つのCRDを導入します。
      • Order
      • Challenge

Order

  • チャレンジ実行の要求を表現する。
  • エンドユーザーが作成することはない。一度作ったら変更されない。

Challenge

  • チャレンジを表現する。
    • 複数ドメインに対する要求を行う場合、Orderひとつにつき複数のChallengeが作成される。
  • Challengeライフサイクル
    • Challengeは、キューにいれられて順次処理される。
    • チャレンジが完了したらChallengeリソースはKubernetesクラスタ上から消える。
  • エンドユーザーが作成することはない。一度作ったら変更されない。

Ingress

  • Kubernetesクラスタ内へのHTTP(S)アクセスを管理するリソース。
    • NginxなどのWebサーバーとして提供される場合や、GCP, AWSなどのマネジメントサービスにおけるロードバランサとして提供される場合がある。
  • SSL/TLS証明書を参照し、SSL終端としての機能を持つ。
    • cert-managerを利用して取得した証明書は、最終的にはIngressが参照・利用することになる。
  • エンドユーザーがmanifestファイルを作成し、管理します。
  • Ingressはcert-managerがCRDとして定義しているリソースではありません。

各登場人物のmanifestファイルサンプル

上述のとおり、以下3つのリソースはユーザーがmanifestファイルを作成・管理する必要があります。

  • Issuer
  • Certificate
  • Ingress

これら3つのリソースのmanifestファイルのサンプルと、その関係性を以下に記載していきます。

Issuer manifestファイルサンプル

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: YOUR_ISSUER_NAME
spec:
  acme:
    email: "hoge@example.com"
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: lets-encrypt
    solvers:
    - dns01:
        cloudDNS:
          project: example-com
          serviceAccountSecretRef:
            name: prod-clouddns-svc-acct-secret
            key: service-account.json

Issuerのmanifestで大切なのはmetadata.namespec以下です。
metadata.nameはそのまんま、このリソースの名前となります。他のリソースからこのリソースを参照するので重要です。
spec以下IssuerのTypeによって変わります。今回はLet's Encryptを使う前提ですので、spec.acmeです。
このmanifestだと、staging環境のLet's Encryptのサーバーに対して、DNS01チャレンジを実行しますよ、GCPのCloudDNSを使いますよ、example-comというGCPプロジェクトのCloudDNSを使うためにprod-clouddns-svc-acct-secretというSecretリソースにサービスアカウントのクレデンシャルを置いていますよ、という内容になります。
他のIssuerTypeを使う場合や、ACMEでも別の設定を選択する場合は公式ドキュメントを参照してください。

https://cert-manager.io/docs/configuration/

Certificate manifestファイルサンプル

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: YOUR_CERTIFICATE_NAME
spec:
  secretName: YOUR_SECRET_NAME
  dnsNames:
  - example.com
  issuerRef:
    name: YOUR_ISSUER_NAME
    kind: Issuer

Certificateコンポーネントのmanifestファイルには、secretName,dnsNames,issuerRefのフィールドが存在します。
dnsNamesで指定したドメインに対する証明書を、issuerRefで指定したIssuerから取得します。
secretNameはKubernetesのSecretリソースの名前を指定します。このSecretに実際の鍵と証明書が保持されることになります。

このmanifestファイルの設定であれば、example.comに対する証明書が、YOUR_ISSUER_NAMEという名前のIssueerから取得され、それぞれの証明書と鍵がYOUR_SECRET_NAMEという名前のSecretリソースに保存されることになります。

実際のSecretに保持される内容の例を以下に示します。

$ kubectl get secret ${YOUR_SECRET_NAME}

apiVersion: v1
kind: Secret
data:
  tls.crt: LS0tLaa.....
  tls.key: LS0tLOU....
  creationTimestamp: "2022-00-00T00:00:00Z"
  labels:
    certmanager.k8s.io/certificate-name: YOUR_SECRET_NAME
  name: YOUR_SECRET_NAME
  namespace: YOUR_NAMESPACE_NAME
...
...

data.tls.crtには証明書、data.tls.keyには鍵の値が入ります。
これらの値を使って暗号通信を実現します。

ちなみに、実際の証明書の値はSecretにだけ存在します。
紛らわしいですが、Certificateリソースに証明書の値は存在しません。
代わりに証明書の失効・更新予定日などの情報を含んでいます。

$ kubectl get Certificate ${YOUR_CERTIFICATE_NAME}

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  creationTimestamp: "2022-01-13T12:19:50Z"
  generation: 1
  name: YOUR_CERTIFICATE_NAME
  namespace: YOUR_NAMESPACE_NAME
spec:
  commonName: example.com
  dnsNames:
  - example.com
  issuerRef:
    kind: Issuer
    name: YOUR_ISSUER_NAME
  secretName: YOUR_SECRET_NAME
status:
  conditions:
  - lastTransitionTime: "2022-01-13T12:19:50Z" # 2022/1/13に作成
    message: Certificate is up to date and has not expired
    observedGeneration: 1
    reason: Ready
    status: "True"
    type: Ready
  notAfter: "2022-04-13T11:21:25Z" # 90日後の2022/4/13に失効
  notBefore: "2022-01-13T11:21:26Z"
  renewalTime: "2022-03-14T11:21:25Z" # 60日後の2022/3/14に更新予定
  revision: 1

Ingress manifestファイルサンプル

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/issuer: YOUR_ISSUER_NAME
  name: YOUR_INGRESS_NAME
  namespace: YOUR_INGRESS_NAME
spec:
  rules:
  - host: example.com
    http:
      paths:
      - pathType: Prefix
        path: /
        backend:
          service:
            name: YOUR_SERVICE_NAME
            port:
              number: 80
  tls:
  - hosts:
    - example.com
    secretName: YOUR_SECRET_NAME

tls.hosts[0].secretNameに、証明書と鍵を保持しているSecretの名前を入れてやることで、Ingressは証明書を参照して、暗号通信を実現します。
つまり、Certificateのmanifest内のspec.secretNameと同じ値を入れてやればOKです。

まとめ

簡単ですが、cert-managerによる証明書取得・利用の流れをmanifestファイルのサンプルを含めて紹介しました。

cert-managerの公式ドキュメントは比較的充実していて、勉強になると感じます。
興味がある方はじっくり読んでみると面白いかもしれません。

Discussion