Kubernetes:Cert-Manager

KubernetesやOpenShift向けのTLS認証を自動化するポッド。Ingress-nginxポッドとセットで利用します(minikube)。

$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml

minikubeでIngressをインストール(アドオンを有効化)

$ minikube addons enable ingress

各ポッドの確認

$ kubectl get pod -A
NAMESPACE       NAME                                       READY   STATUS              RESTARTS      AGE
cert-manager    cert-manager-6468fc8f56-r49lz              0/1     ContainerCreating   0             18s
cert-manager    cert-manager-cainjector-7fd85dcc7-w8wv2    1/1     Running             0             18s
cert-manager    cert-manager-webhook-57df45f686-xq5xx      0/1     Running             0             18s
ingress-nginx   ingress-nginx-admission-create-vbdbs       0/1     Completed           0             22m
ingress-nginx   ingress-nginx-admission-patch-jrvlt        0/1     Completed           0             22m
ingress-nginx   ingress-nginx-controller-67c5cb88f-p4c87   1/1     Running             0             22m
kube-system     coredns-674b8bbfcf-pjstq                   1/1     Running             0             27m
kube-system     etcd-minikube                              1/1     Running             0             27m
kube-system     kindnet-mb8jv                              1/1     Running             0             27m
kube-system     kube-apiserver-minikube                    1/1     Running             0             27m
kube-system     kube-controller-manager-minikube           1/1     Running             0             27m
kube-system     kube-proxy-wxjc7                           1/1     Running             0             27m
kube-system     kube-scheduler-minikube                    1/1     Running             0             27m
kube-system     storage-provisioner                        1/1     Running             1 (27m ago)   27m

Cloudflare + Let’s Encrypt : DNS-01チャレンジ

KubernetesにAPIトークンをシークレットとして保存

cert-managerはsecretを探す際、以下のルールで動作

  • ClusterIssuerを使っている場合:

    secret はcert-managerのNamespace(通常は cert-manager)に作成する必要があります。これは ClusterIssuer が「クラスタ全体で共有」されるため、Namespace に依存しないリソースだからです。

  • Issuerを使っている場合:

    secret は、そのIssuerが存在するNamespaceに作成する必要があります。

$ kubectl create secret generic cloudflare-api-token-secret \
  --from-literal=api-token='YOUR_CLOUDFLARE_API_TOKEN' -n cert-manager

ClusterIssuerの作成

cluster-issuer.yaml

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns
spec:
  acme:
    email: [email protected]
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-dns-private-key
    solvers:
    - dns01:
        cloudflare:
          email: [email protected]
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token

適用

$ kubectl apply -f cluster-issuer.yaml

Apacheポット(Deployment+Service)を用意

apache-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: apache
spec:
  replicas: 1
  selector:
    matchLabels:
      app: apache
  template:
    metadata:
      labels:
        app: apache
    spec:
      containers:
      - name: apache
        image: httpd:alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: apache-service
spec:
  selector:
    app: apache
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

適用

$ kubectl apply -f apache-deployment.yaml

Certificateリソースの作成(TLS証明書)

注01) このファイルは手動で認証取得する場合の設定で、以下のIngressで自動取得する設定をした場合には必要ありません。

  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-dns

certificate.yaml

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-cert
  namespace: default
spec:
  secretName: wildcard-cert-tls
  issuerRef:
    name: letsencrypt-dns
    kind: ClusterIssuer
  commonName: example.com
  dnsNames:
    - example.com
    - '*.example.com'

適用

$ kubectl apply -f certificate.yaml

Ingressの作成(TLSと統合)

ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-dns
spec:
  tls:
    - hosts:
        - example.com
        - www.example.com
      secretName: wildcard-cert-tls
  rules:
    - host: example.com
      http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: my-service
              port:
                number: 80

適用

$ kubectl apply -f ingress.yaml

実行順序

$ kubectl create secret generic cloudflare-api-token-secret \
  --from-literal=api-token='YOUR_CLOUDFLARE_API_TOKEN' -n cert-manager
$ kubectl apply -f cluster-issuer.yaml
clusterissuer.cert-manager.io/letsencrypt-dns created
$ kubectl apply -f certificate.yaml ### 注01)参照 
certificate.cert-manager.io/wildcard-cert created ### 注01)参照 
$ kubectl apply -f ingress.yaml
Warning: annotation "kubernetes.io/ingress.class" is deprecated, please use 'spec.ingressClassName' instead
ingress.networking.k8s.io/my-ingress created

TLS認証リソースの確認

$ kubectl get certificate 
NAME                READY   SECRET              AGE
wildcard-cert-tls   True    wildcard-cert-tls   177m

TLS認証リソース詳細

$ kubectl get certificate wildcard-cert-tls -n default -o yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  creationTimestamp: "2025-06-07T05:36:44Z"
  generation: 1
  name: wildcard-cert-tls
  namespace: default
  ownerReferences:
  - apiVersion: networking.k8s.io/v1
    blockOwnerDeletion: true
    controller: true
    kind: Ingress
    name: my-ingress
....
....
....

Secretから証明書と秘密鍵を抽出

$ kubectl get secret wildcard-cert-tls -n default -o jsonpath="{.data['tls\.crt']}" | base64 -d > tls.crt
$ kubectl get secret wildcard-cert-tls -n default -o jsonpath="{.data['tls\.key']}" | base64 -d > tls.key

証明書の中身を確認(対象ドメインは Subject Alternative Name として示されます)

$ openssl x509 -in tls.crt -text -noout
.....
.....
X509v3 Subject Alternative Name: 
                DNS:sub1.example.com, DNS:sub2.example.com, DNS:sub3.example.com
.....
.....

Kubernetesでは、ポッド内コンテナへのアクセスはServiceというリソースを介して行われます。

Service:Serviceの入口であるportとポッド(コンテナ)の開放ポート:targetPortを設定。

NodePort:Serviceへ接続するためのホスト(Node)側ポート
ホスト(Node)上の固定ポート(通常 30000–32767)を Service に割り当てます。

NodePortを指定すると、<ホスト(Node)IP>:<nodePort>で外部からアクセス可。

注)NodePortを使わなくてもIngresshostNetwork、クラウドのLoadBalancerなどの手段で外部からアクセスすることも可能です。


各 IP の役割

種類 割当例 説明
Node IP 192.168.1.141 実際のノードのIP。NodePortが使う
Pod IP 10.244.1.15 各Podが持つ仮想IP。CNIによって管理される
Service IP 10.96.0.10 Podへの安定した入口。Podの前に立つ仮想IP