根据K8S文档描述, Kubernetes API Server 通过HTTPS POST访问Webhook Server, 也就是说Webhook Server 必须要监听在HTTPS协议上.
要使用HTTPS协议, 有3个东西是必须的: ca, key, cert.
其中ca 是指ca 证书, key 是指服务器使用使用的私钥, cert 指公钥, 一般也称为服务器证书.
API-Server 在访问Webhook server 的时候, 要指定ca证书
Webhook Server在启动的时候, 要加载key和cert.
社区推荐使用Cert-Manager来为webhook 提供证书管理服务.
本文不讨论Cert-Manager的工作原理, 而是从使用者的角度来介绍如何利用Cert-Manager为Webhook配置证书.
cert-manager is a native Kubernetes certificate management controller. It can help with issuing certificates from a variety of sources, such as Let’s Encrypt, HashiCorp Vault, Venafi, a simple signing key pair, or self signed.
Cert-Manager 的基本概念
要使用cert-manager, 需要先了解这几个概念: Issuers, Certificate, ca injector.
Issuers
Issuers 是cert-manager 定义的k8s resource, 相当于证书颁发机构, 用于生成证书.
Issuers 又分为 Issuer 和 ClusterIssuer:
Issuer 是 namespace level 的 issuer, 可以为其所在的namespace 提供证书.
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
...
spec:
...
ClusterIssuer 是 cluster level 的issuer, 可以为集群内所有namespace 提供证书.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
...
spec:
...
Certificate
Certificate 是 cert-manager 在 k8s 中定义的一种资源, 属于 namespace level.
cert-manager 会根据certificate的定义结合issuer来创建真正的证书对(cert-pair)
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: webhook-cert
namespace: {{ .Release.Namespace }}
spec:
dnsNames:
- webhook.{{ .Release.Namespace }}.svc
- webhook.{{ .Release.Namespace }}.svc.cluster.local
issuerRef:
kind: Issuer
name: selfsigned-issuer
secretName: webhook-server-cert
CA Injector
CA Injector 是cert-manager的一个controller. 它可以将caBundle 字段写入到这三个K8S Resource中:
ValidatingWebhookConfiguration
MutatingWebhookConfiguration
CustomResourceDefinition
要使用CA Injector, 需要在webhook的yaml中添加 annotation: cert-manager.io/inject-ca-from
. 告诉CA Injector, 要将哪一个证书写到cabundle中.
例如:
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
...
annotations:
cert-manager.io/inject-ca-from: example1/webhook1-certificate
webhooks:
...
这个例子表示将使用namespace example1下的 secret webhook-certificate 的ca 填充到cabundle中.
试一试
1. 部署Cert-Manager
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.3/cert-manager.yaml
2. 创建 Issuer
通常来讲, 为webhook-server 颁发证书使用自签名证书即可, 因为除了K8S API Server, 没有其他外部服务会去访问webhook.
issuer.yaml:
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
namespace: default
spec:
selfSigned: {}
创建
$ kubectl apply -f issuer.yaml
$ kubectl get issuers selfsigned-issuer -o wide
NAME READY STATUS AGE
selfsigned-issuer True 2m7s
3. 创建Certificate
现在我们要创建certificate, 一个certificate最基本的要包含dnsNames 和 issuerRef.
dnsNames 表示这个证书签发给哪个域名.
issuerRef 表示使用哪个issuer来签发这个证书.
最后还需要secretName, 表示证书存放在哪个secret里面.
cert.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: luna-cert
namespace: default
spec:
dnsNames:
- luna-webhook.default.svc
- luna-webhook.default.svc.cluster.local
issuerRef:
kind: Issuer
name: selfsigned-issuer
secretName: luna-cert
创建证书
$ kubectl apply -f cert.yaml
$ k get certificate luna-cert
NAME READY SECRET AGE
luna-cert True luna-cert 1m
4. 创建Webhook
webhook.yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
annotations:
cert-manager.io/inject-ca-from: default/luna-cert
name: luna-validating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1beta1
clientConfig:
service:
name: luna-webhook
namespace: default
path: /luna-validate-webhook
port: 443
failurePolicy: Fail
matchPolicy: Equivalent
name: vservice
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- services
scope: '*'
sideEffects: None
timeoutSeconds: 10
创建
kubectl apply -f webhook.yaml
现在再看刚刚创建的webhook, 发现caBundle已经被填充进去了.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
...
annotations:
cert-manager.io/inject-ca-from: default/luna-cert
webhooks:
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMrakNDQWVLZ0F3SUJBZ0lRSjFwc3ZsdmZsNlNabUhvWFI3SUVBekFOQmdrcWhraUc5dzBCQVFzRkFEQUEKTUI0WERUSXdNVEF5TWpFeU1ESXdOMW9YRFRJeE1ERXlNREV5TURJd04xb3dBRENDQVNJd0RRWUpLb1pJaHZjTgpBUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBS3M2czAxR1FRa3R6VGZUQXRBTkV3RnJ1RS95WEVINmxQaVhwTGoyCnIzQjBQZkFLem1wZDdYd2QrbUxaNnA1aytDdEFKc293ZU5lRUNDd3prZE1Ha3p0cE1zK1huZ1d1dTVsajJZVUwKaW81Tm5TMjVYaHkxYlZOb0Y0SENuMGlrMWxLTXZBZnBEMXlKeDBkalY4TzcrdkMwL2NkN25BanMzbFcrVnVCcwpUT2tlY1g4elJ2YVBnd1pGRUd3SjR2MmRITGVsZjBvbkdRU25yRWZvMEE5am9DaGFGWkdzcEUrTEwwdm5mOWhXCkYzVVVLaFIrd25PdnZOajJYa2dzaktPYmRtUVpEaENBbDJxekw2cGNYZ2xPc21hTjVTMEJaYm5SSWRIZERBU1gKVGN1Nk42QzJjcUlHNnA3OW5ZeXZMajFaM0diTFdnODl0M3hSRGhxUkZleDdVaDBDQXdFQUFhTndNRzR3RGdZRApWUjBQQVFIL0JBUURBZ1dnTUF3R0ExVWRFd0VCL3dRQ01BQXdUZ1lEVlIwUkFRSC9CRVF3UW9JWWJIVnVZUzEzClpXSm9iMjlyTG1SbFptRjFiSFF1YzNaamdpWnNkVzVoTFhkbFltaHZiMnN1WkdWbVlYVnNkQzV6ZG1NdVkyeDEKYzNSbGNpNXNiMk5oYkRBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQW8wOS9QWGR2OCtYV0RMd1k5S2tTRjYyNApySGpoQkJpL0RMWExLTGFMa1NlUEpuSCtwcGQ2cmt4ejJudkpKWnVBTzhKYmlrR3o0ZkFsUkhqSmFxR3oxV1JhCkQ2ellXZ0NmWHQ3RVlJejJXZm50OVpNbnBWRU9wcEUrUnJ1QURBcnVsRGlJTk5Xc1dtOFluK3lWc3gvbkF5MVYKRk9HbEJ3aE1FNEdHLzZlNERFd2hFalpWR3FOMVlxcFFWOUJCQXhrZVhBcHMzTWMwS1EzTDlJMHlUZzdrdHdNYQp1eVdaU0t0SDZtMTFoNE1ueFBXcHJHTlNTTExwMytNcXlvMnI1Q25Rd0J3QmR4Rmg4NWFCaWhyOVd4K2NxejZkCjFrKzdxSEc2SEFVQjVCVGtRZ0hvWnpkR2VJN3pldXFsSG8wa2lZMlRNdkIvSEVSd21WQ3BsNXNsTXB1azJRPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
总结:
上面我展示了: 利用Cert-Manager自动为Webhook颁发证书.一个证书其实包含3方面内容, 可以查看Certificate 的 secret.
$ kubectl describe secrets luna-cert
Name: luna-cert
Namespace: default
Labels: <none>
Annotations: cert-manager.io/alt-names: luna-webhook.default.svc,luna-webhook.default.svc.cluster.local
cert-manager.io/certificate-name: luna-cert
cert-manager.io/common-name:
cert-manager.io/ip-sans:
cert-manager.io/issuer-group:
cert-manager.io/issuer-kind: Issuer
cert-manager.io/issuer-name: selfsigned-issuer
cert-manager.io/uri-sans:
Type: kubernetes.io/tls
Data
====
ca.crt: 1094 bytes
tls.crt: 1094 bytes
tls.key: 1675 bytes
这里展示的是Cert-Manager将ca.crt 填充到webhook的cabundle中.
另外两个tls.crt, tls.key需要挂载到webhook所在的pod中. 如果你用的是kubebuilder, 目录应该是 /tmp/k8s-webhook-server/serving-certs
luna-deployment.yaml
template:
spec:
containers:
- name: luna
image: harbor.inner.galaxy.ksyun.com/galaxy/luna-controller:0.1.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8443
name: webhook
protocol: TCP
volumeMounts:
- mountPath: /tmp/k8s-webhook-server/serving-certs
name: cert
readOnly: true
volumes:
- name: cert
secret:
defaultMode: 420
secretName: luna-cert