配置使用cert-manager

发布于 2019年07月11日

概述

一直对cert-manager项目很感兴趣,今天着重研究了一下他的架构,并做了个尝试,这里做个记录。

cert-manager简介

它支持从Let’s Encrypt,HashiCorp Vault,Venafi等颁发证书。

架构如下:

它由以下组件组成:

Issuer

Issuer和ClusterIssuers是Kubernetes资源,它们代表证书颁发机构(CA),能够通过执行证书签名请求来生成签名证书。

Issuers只能在当前命名空间下使用,如果要创建可以在多个名称空间中使用的单个Issuer,则应考虑创建ClusterIssuer资源。

它支持的证书颁发机构如下:

[Configuration | cert-manager](https://cert-manager.io/docs/configuration/)

Certificate

“Certificate”定义了所需的x509证书,该证书将被更新并保持最新状态。证书是一个命名空间资源,它引用Issuer或ClusterIssuer,它们确定将接受证书请求的内容。

CertificateRequest

CertificateRequest是cert-manager中的命名空间资源,用于从颁发者请求x509证书。该资源包含PEM编码的证书请求的base64编码的字符串,该字符串被发送到引用的Issuer。成功发行后,将根据证书签名请求返回已签名的证书。证书请求通常由控制器或其他系统使用和管理,除非特别需要,否则不应由我们自己使用。

ACME Orders and Challenges

cert-manager支持使用ACME颁发者向ACME服务器(包括Let’s Encrypt)请求证书。大多数计算机通常在公共Internet上信任这些证书。要成功请求证书,证书管理者必须解决ACME Challenges,这些Challenges必须完成才能证明客户端拥有所请求的DNS地址。

为了完成 Challenges,cert-manager引入了两种CustomResource类型,Order与Challenge。

ACME使用Orders资源来管理签名的TLS证书的ACME“Order”的生命周期。Order代表单个证书申请,一旦创建了引用ACME颁发者的新CertificateRequest资源,该订单便会自动创建。创建证书资源,更改其规范或需要更新证书资源后,cert-manager会自动创建CertificateRequest资源。

作为最终用户,您将不需要手动创建Order资源。创建后,便无法更改Order。而是,必须创建一个新的Order资源。

Order资源为该“订单”封装了多个ACME Challenges,因此将管理一个或多个Challenges资源。

ACME Issuer使用Challenge资源来管理必须完成的ACME Challenge的生命周期,以完成单个DNS名称/标识符的“授权”。

创建Order资源后,订单控制器将为ACME服务器授权的每个DNS名称创建Challenge资源。

作为最终用户,您将无需手动创建Challenge资源。创建Challenge后,便无法更改。相反,必须创建一个新的Challenge资源。

Webhook

cert-manager利用Webhook服务器扩展Kubernetes API服务器,以提供对cert-manager资源的动态准入控制。

Webhook组件被部署为另一个Pod,与主要的证书管理器控制器和CA注入器组件一起运行。

为了使API服务器与webhook组件进行通信,webhook需要配置为apiserver信任的TLS证书。

为了使API服务器与webhook组件进行通信,webhook需要配置为apiserver信任的TLS证书。这是由cainjector创建的,并由以下两个secret实现:

secret /cert-manager-webhook-ca:一种自签名的根CA证书,用于签署Webhook容器的证书。

secret /cert-manager-webhook-tls:由上面的根CA颁发的TLS证书,由Webhook提供。

CA Injector

证书管理器CA注入程序控制器负责将CA捆绑软件注入到Webhook的ValidatingWebhookConfiguration和MutatingWebhookConfiguration资源中,以允许Kubernetes API服务器“信任” Webhook API服务器。

## 配置使用(v0.12.0)

1. 下载并配置crd资源

wget -c https://raw.githubusercontent.com/jetstack/cert-manager/release-0.12/deploy/manifests/00-crds.yaml

kubectl apply -f 00-crds.yaml

2. 下载,这里选择v0.12.0,并解压

helm fetch --untar jetstack/cert-manager --version v0.12.0

3. 编辑values.yaml

#修改安装的node结点

#94

nodeSelector:

  node: sre

…

#160

nodeSelector:

  node: sre

#207

nodeSelector:

  node: sre

4. 通过helm安装cert-manager

kubectl create ns cert-manager

helm install  cert-manager -n  cert-manager -f values.yaml ./

5. 验证cert-manager是否安装正确

#创建如下测试资源test-resources.yaml

apiVersion: v1

kind: Namespace

metadata:

  name: cert-manager-test

---

apiVersion:  cert-manager.io/v1alpha2

kind: Issuer

metadata:

  name: test-selfsigned

  namespace: cert-manager-test

spec:

  selfSigned: {}

---

apiVersion:  cert-manager.io/v1alpha2

kind: Certificate

metadata:

  name: selfsigned-cert

  namespace: cert-manager-test

spec:

  commonName: example.com

  secretName: selfsigned-cert-tls

  issuerRef:

    name: test-selfsigned

# 执行以下命令

kubectl apply -f test-resources.yaml

# 观察以下命令输出,最后一行看到Certificate issued successfully,就代表安装成功

kubectl describe certificate -n cert-manager-test

# 清空测试

kubectl delete -f test-resources.yaml

6. 安装alidns-webhook,这里选择官方推荐的alidns-webhook,[DNS01 | cert-manager](https://cert-manager.io/docs/configuration/acme/dns01/)

#下载alidns-webhook

git clone https://github.com/pragkent/alidns-webhook

#执行以下安装,cert-manager的v0.11以上,选择bundle.yaml版本

kubectl apply -f deploy/bundle.yaml

#创建secret

kubectl -n cert-manager create secret generic alidns-secret --from-literal=access-key=‘xxxxx’ --from-literal=secret-key=‘xxxx’

7. 创建ClusterIssuer

apiVersion: cert-manager.io/v1alpha2

kind: ClusterIssuer

metadata:

  name: letsencrypt-prod

spec:

  acme:

    email: xxx@example.org

    server: https://acme-v02.api.letsencrypt.org/directory

    privateKeySecretRef:

      name: letsencrypt-prod-account-key

    solvers:

    - dns01:

        webhook:

          groupName: acme.yourcompany.com

          solverName: alidns

          config:

            region: ""

            accessKeySecretRef:

              name: alidns-secret

              key: access-key

            secretKeySecretRef:

              name: alidns-secret

              key: secret-key

8. 创建测试ingress

#创建以下yarn文件,test-ingress.yaml

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: test-ingress

  namespace: test

  annotations:

    cert-manager.io/cluster-issuer: "letsencrypt-prod"

spec:

  tls:

  - hosts:

    - 'test-ingress.yourdomain.com'

    secretName: test-ingress1-yourdomain-com-tls

  rules:

  - host: test-yourdomain.insyunmi.com

    http:

      paths:

      - path: /

        backend:

          serviceName: mynginx

          servicePort: 80

---

apiVersion: apps/v1

kind: Deployment

metadata:

  labels:

    run: mynginx

  name: mynginx

  namespace: test

spec:

  replicas: 1

  selector:

    matchLabels:

      run: mynginx

  template:

    metadata:

      labels:

        run: mynginx

    spec:

      containers:

      - image: nginx

        imagePullPolicy: Always

        name: mynginx

        ports:

        - containerPort: 80

          protocol: TCP

---

apiVersion: v1

kind: Service

metadata:

  name: mynginx

  namespace: test

spec:

  ports:

  - port: 80

    protocol: TCP

    targetPort: 80

  selector:

    run: mynginx

#执行

kubectl apply -f test-ingress.yaml

9. 查看生成的证书

kubectl get certificates -n test

NAME                             READY   SECRET                           AGE

test-ingress1-yourdomain-com-tls   True    test-ingress1-yourdomain-com-tls   106m

总结

  1. 在安装使用alidns-webhook时,需要注意,alidns-webhook给出的示例是letsencrypt测试环境,实际使用时,需要改为正式环境。

  2. 配置完后,只需要在ingress中增加以下annotations:cert-manager.io/cluster-issuer: "letsencrypt-prod"



评论