Merge pull request #33277 from howieyuen/managing-tls-in-a-cluster

[zh]resync tls task: Manage TLS Certificates in a Cluster
pull/33281/head
Kubernetes Prow Robot 2022-04-28 03:57:51 -07:00 committed by GitHub
commit d0a46e83bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 285 additions and 97 deletions

View File

@ -29,49 +29,78 @@ Kubernetes 提供 `certificates.k8s.io` API可让你配置由你控制的证
{{< note >}}
<!--
Certificates created using the `certificates.k8s.io` API are signed by a
dedicated CA. It is possible to configure your cluster to use the cluster root
[dedicated CA](#a-note-to-cluster-administrators). It is possible to configure your cluster to use the cluster root
CA for this purpose, but you should never rely on this. Do not assume that
these certificates will validate against the cluster root CA.
-->
使用 `certificates.k8s.io` API 创建的证书由指定 CA 颁发。将集群配置为使用集群根目录
CA 可以达到这个目的,但是你永远不要依赖这一假定。不要以为
这些证书将针对群根目录 CA 进行验证。
使用 `certificates.k8s.io` API 创建的证书由指定 [CA](#a-note-to-cluster-administrators) 颁发。
将集群配置为使用集群根目录 CA 可以达到这个目的,但是你永远不要依赖这一假定。
不要以为这些证书将针对群根目录 CA 进行验证。
{{< /note >}}
## {{% heading "prerequisites" %}}
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
{{< include "task-tutorial-prereqs.md" >}}
<!--
You need the `cfssl` tool. You can download `cfssl` from
[https://github.com/cloudflare/cfssl/releases](https://github.com/cloudflare/cfssl/releases).
Some steps in this page use the `jq` tool. If you don't have `jq`, you can
install it via your operating system's software sources, or fetch it from
[https://stedolan.github.io/jq/](https://stedolan.github.io/jq/).
-->
你需要 `cfssl` 工具。
你可以从 [https://github.com/cloudflare/cfssl/releases](https://github.com/cloudflare/cfssl/releases)
下载 `cfssl`
本文中某些步骤使用 `jq` 工具。如果你没有 `jq`,你可以通过操作系统的软件源安装,
或者从 [https://stedolan.github.io/jq/](https://stedolan.github.io/jq/) 获取。
<!-- steps -->
<!--
## Trusting TLS in a Cluster
## Trusting TLS in a cluster
Trusting the custom CA from an application running as a pod usually requires
Trusting the [custom CA](#a-note-to-cluster-administrators) from an application running as a pod usually requires
some extra application configuration. You will need to add the CA certificate
bundle to the list of CA certificates that the TLS client or server trusts. For
example, you would do this with a golang TLS config by parsing the certificate
chain and adding the parsed certificates to the `RootCAs` field in the
[`tls.Config`](https://godoc.org/crypto/tls#Config) struct.
You can distribute the CA certificate as a
[ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap) that your
pods have access to use.
[`tls.Config`](https://pkg.go.dev/crypto/tls#Config) struct.
-->
## 集群中的 TLS 信任
信任 Pod 中运行的应用程序所提供的 CA 通常需要一些额外的应用程序配置。
信任 Pod 中运行的应用程序所提供的[自定义 CA](#a-note-to-cluster-administrators) 通常需要一些额外的应用程序配置。
你需要将 CA 证书包添加到 TLS 客户端或服务器信任的 CA 证书列表中。
例如,你可以使用 Golang TLS 配置通过解析证书链并将解析的证书添加到
[`tls.Config`](https://godoc.org/crypto/tls#Config) 结构中的 `RootCAs`
[`tls.Config`](https://pkg.go.dev/crypto/tls#Config) 结构中的 `RootCAs`
字段中。
你可以用你的应用能够访问到的
[ConfigMap](/zh/docs/tasks/configure-pod-container/configure-pod-configmap)
的形式来发布 CA 证书。
{{< note >}}
<!--
Even though the custom CA certificate may be included in the filesystem (in the
ConfigMap `kube-root-ca.crt`),
you should not use that certificate authority for any purpose other than to verify internal
Kubernetes endpoints. An example of an internal Kubernetes endpoint is the
Service named `kubernetes` in the default namespace.
If you want to use a custom certificate authority for your workloads, you should generate
that CA separately, and distribute its CA certificate using a
[ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap) that your pods
have access to read.
-->
即使自定义 CA 证书可能包含在文件系统中(在 ConfigMap `kube-root-ca.crt` 中),
除了验证内部 Kubernetes 端点之外,你不应将该证书颁发机构用于任何目的。
内部 Kubernetes 端点的一个示例是默认命名空间中名为 `kubernetes` 的服务。
如果你想为你的工作负载使用自定义证书颁发机构,你应该单独生成该 CA
并使用你的 Pod 有读权限的 [ConfigMap](/zh/docs/tasks/configure-pod-container/configure-pod-configmap)
分发该 CA 证书。
{{< /note >}}
<!--
## Requesting a Certificate
## Requesting a certificate
The following section demonstrates how to create a TLS certificate for a
Kubernetes service accessed through DNS.
@ -90,17 +119,7 @@ This tutorial uses CFSSL: Cloudflare's PKI and TLS toolkit [click here](https://
{{< /note >}}
<!--
## Download and install CFSSL
The cfssl tools used in this example can be downloaded at
[https://github.com/cloudflare/cfssl/releases](https://github.com/cloudflare/cfssl/releases).
-->
## 下载并安装 CFSSL
本例中使用的 cfssl 工具可以在 [github.com/cloudflare/cfssl/releases](https://github.com/cloudflare/cfssl/releases) 下载。
<!--
## Create a Certificate Signing Request
## Create a certificate signing request
Generate a private key and certificate signing request (or CSR) by running
the following command:
@ -118,16 +137,11 @@ cat <<EOF | cfssl genkey - | cfssljson -bare server
"192.0.2.24",
"10.0.34.2"
],
"CN": "system:node:my-pod.my-namespace.pod.cluster.local",
"CN": "my-pod.my-namespace.pod.cluster.local",
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"O": "system:nodes"
}
]
}
}
EOF
```
@ -136,37 +150,37 @@ EOF
Where `192.0.2.24` is the service's cluster IP,
`my-svc.my-namespace.svc.cluster.local` is the service's DNS name,
`10.0.34.2` is the pod's IP and `my-pod.my-namespace.pod.cluster.local`
is the pod's DNS name. You should see the following output:
is the pod's DNS name. You should see the output similar to:
-->
其中 `192.0.2.24` 是服务的集群 IP`my-svc.my-namespace.svc.cluster.local`
是服务的 DNS 名称,`10.0.34.2` 是 Pod 的 IP
`my-pod.my-namespace.pod.cluster.local` 是 Pod 的 DNS 名称。
你能看到以下的输出:
你能看到的输出类似于
```
2017/03/21 06:48:17 [INFO] generate received request
2017/03/21 06:48:17 [INFO] received CSR
2017/03/21 06:48:17 [INFO] generating key: ecdsa-256
2017/03/21 06:48:17 [INFO] encoded CSR
2022/02/01 11:45:32 [INFO] generate received request
2022/02/01 11:45:32 [INFO] received CSR
2022/02/01 11:45:32 [INFO] generating key: ecdsa-256
2022/02/01 11:45:32 [INFO] encoded CSR
```
<!--
This command generates two files; it generates `server.csr` containing the PEM
encoded [pkcs#10](https://tools.ietf.org/html/rfc2986) certification request,
encoded [PKCS#10](https://tools.ietf.org/html/rfc2986) certification request,
and `server-key.pem` containing the PEM encoded key to the certificate that
is still to be created.
-->
此命令生成两个文件;它生成包含 PEM 编码
[pkcs#10](https://tools.ietf.org/html/rfc2986) 证书请求的 `server.csr`
[PKCS#10](https://tools.ietf.org/html/rfc2986) 证书请求的 `server.csr`
以及 PEM 编码密钥的 `server-key.pem`,用于待生成的证书。
<!--
## Create a Certificate Signing Request object to send to the Kubernetes API
## Create a CertificateSigningRequest object to send to the Kubernetes API
Generate a CSR yaml blob and send it to the apiserver by running the following
command:
-->
## 创建证书签名请求对象发送到 Kubernetes API
## 创建证书签名请求CSR对象发送到 Kubernetes API
使用以下命令创建 CSR YAML 文件,并发送到 API 服务器:
@ -178,7 +192,7 @@ metadata:
name: my-svc.my-namespace
spec:
request: $(cat server.csr | base64 | tr -d '\n')
signerName: kubernetes.io/kubelet-serving
signerName: example.com/serving
usages:
- digital signature
- key encipherment
@ -188,9 +202,9 @@ EOF
<!--
Notice that the `server.csr` file created in step 1 is base64 encoded
and stashed in the `.spec.request` field. We are also requesting a
and stashed in the `.spec.request` field. You are also requesting a
certificate with the "digital signature", "key encipherment", and "server
auth" key usages, signed by the `kubernetes.io/kubelet-serving` signer.
auth" key usages, signed by an example `example.com/serving` signer.
A specific `signerName` must be requested.
View documentation for [supported signer names](/docs/reference/access-authn-authz/certificate-signing-requests/#signers)
for more information.
@ -199,9 +213,9 @@ The CSR should now be visible from the API in a Pending state. You can see
it by running:
-->
请注意,在步骤 1 中创建的 `server.csr` 文件是 base64 编码并存储在
`.spec.request` 字段中的。我们还要求提供 “digital signature数字签名
`.spec.request` 字段中的。还要求提供 “digital signature数字签名
“密钥加密key encipherment” 和 “服务器身份验证server auth” 密钥用途,
`kubernetes.io/kubelet-serving` 签名程序签名的证书。
`example.com/serving` 示例签名程序签名的证书。
你也可以要求使用特定的 `signerName`。更多信息可参阅
[支持的签署者名称](/zh/docs/reference/access-authn-authz/certificate-signing-requests/#signers)。
@ -215,28 +229,30 @@ kubectl describe csr my-svc.my-namespace
Name: my-svc.my-namespace
Labels: <none>
Annotations: <none>
CreationTimestamp: Tue, 21 Mar 2017 07:03:51 -0700
CreationTimestamp: Tue, 01 Feb 2022 11:49:15 -0500
Requesting User: yourname@example.com
Signer: example.com/serving
Status: Pending
Subject:
Common Name: my-svc.my-namespace.svc.cluster.local
Common Name: my-pod.my-namespace.pod.cluster.local
Serial Number:
Subject Alternative Names:
DNS Names: my-svc.my-namespace.svc.cluster.local
DNS Names: my-pod.my-namespace.pod.cluster.local
my-svc.my-namespace.svc.cluster.local
IP Addresses: 192.0.2.24
10.0.34.2
Events: <none>
```
<!--
## Get the Certificate Signing Request Approved
## Get the CertificateSigningRequest approved {#get-the-certificate-signing-request-approved}
Approving the [certificate signing request](/docs/reference/access-authn-authz/certificate-signing-requests/)
is either done by an automated approval process or on a one off basis by a cluster
administrator. If you're authorized to approve a certificate request, you can do that
manually using `kubectl`; for example:
-->
## 批准证书签名请求
## 批准证书签名请求CSR {#get-the-certificate-signing-request-approved}
[证书签名请求](/zh/docs/reference/access-authn-authz/certificate-signing-requests/)
的批准或者是通过自动批准过程完成的,或由集群管理员一次性完成。
@ -250,29 +266,167 @@ kubectl certificate approve my-svc.my-namespace
certificatesigningrequest.certificates.k8s.io/my-svc.my-namespace approved
```
<!--
## Download the Certificate and Use It
Once the CSR is signed and approved you should see the following:
-->
## 下载证书并使用它
CSR 被签署并获得批准后,你应该看到以下内容:
<!-- You should now see the following: -->
你现在应该能看到如下输出:
```shell
kubectl get csr
```
```none
NAME AGE REQUESTOR CONDITION
my-svc.my-namespace 10m yourname@example.com Approved,Issued
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
my-svc.my-namespace 10m example.com/serving yourname@example.com <none> Approved
```
<!--
This means the certificate request has been approved and is waiting for the
requested signer to sign it.
-->
这意味着证书请求已被批准,并正在等待请求的签名者对其签名。
<!--
## Sign the CertificateSigningRequest {#sign-the-certificate-signing-request}
Next, you'll play the part of a certificate signer, issue the certificate, and upload it to the API.
A signer would typically watch the CertificateSigningRequest API for objects with its `signerName`,
check that they have been approved, sign certificates for those requests,
and update the API object status with the issued certificate.
-->
## 签名证书签名请求CSR {#sign-the-certificate-signing-request}
接下来,你将扮演证书签署者的角色,颁发证书并将其上传到 API 服务器。
签名者通常会使用其 `signerName` 查看对象的 CertificateSigningRequest API
检查它们是否已被批准,为这些请求签署证书,并使用已颁发的证书更新 API 对象状态。
<!--
### Create a Certificate Authority
You need an authority to provide the digital signature on the new certificate.
First, create a signing certificate by running the following:
-->
### 创建证书颁发机构
你需要授权在新证书上提供数字签名。
首先,通过运行以下命令创建签名证书:
```shell
cat <<EOF | cfssl gencert -initca - | cfssljson -bare ca
{
"CN": "My Example Signer",
"key": {
"algo": "rsa",
"size": 2048
}
}
EOF
```
<!-- You should see output similar to: -->
你应该看到类似于以下的输出:
```none
2022/02/01 11:50:39 [INFO] generating a new CA key and certificate from CSR
2022/02/01 11:50:39 [INFO] generate received request
2022/02/01 11:50:39 [INFO] received CSR
2022/02/01 11:50:39 [INFO] generating key: rsa-2048
2022/02/01 11:50:39 [INFO] encoded CSR
2022/02/01 11:50:39 [INFO] signed certificate with serial number 263983151013686720899716354349605500797834580472
```
<!--
This produces a certificate authority key file (`ca-key.pem`) and certificate (`ca.pem`).
-->
这会产生一个证书颁发机构密钥文件(`ca-key.pem`)和证书(`ca.pem`)。
<!-- ### Issue a certificate -->
### 颁发证书
{{< codenew file="tls/server-signing-config.json" >}}
<!--
Use a `server-signing-config.json` signing configuration and the certificate authority key file
and certificate to sign the certificate request:
-->
使用 `server-signing-config.json` 签名配置、证书颁发机构密钥文件和证书来签署证书请求:
```shell
kubectl get csr my-svc.my-namespace -o jsonpath='{.spec.request}' | \
base64 --decode | \
cfssl sign -ca ca.pem -ca-key ca-key.pem -config server-signing-config.json - | \
cfssljson -bare ca-signed-server
```
<!-- You should see output similar to: -->
你应该看到类似于以下的输出:
```
2022/02/01 11:52:26 [INFO] signed certificate with serial number 576048928624926584381415936700914530534472870337
```
<!-- This produces a signed serving certificate file, `ca-signed-server.pem`. -->
这会生成一个签名的服务证书文件,`ca-signed-server.pem`。
<!--
### Upload the signed certificate
Finally, populate the signed certificate in the API object's status:
-->
### 上传签名证书
最后,在 API 对象的状态中填充签名证书:
```shell
kubectl get csr my-svc.my-namespace -o json | \
jq '.status.certificate = "'$(base64 ca-signed-server.pem | tr -d '\n')'"' | \
kubectl replace --raw /apis/certificates.k8s.io/v1/certificatesigningrequests/my-svc.my-namespace/status -f -
```
{{< note >}}
<!--
This uses the command line tool [`jq`](https://stedolan.github.io/jq/) to populate the base64-encoded
content in the `.status.certificate` field.
If you do not have `jq`, you can also save the JSON output to a file, populate this field manually, and
upload the resulting file.
-->
这使用命令行工具 [`jq`](https://stedolan.github.io/jq/)
`.status.certificate` 字段中填充 base64 编码的内容。
如果你没有 `jq` 工具,你还可以将 JSON 输出保存到文件中,手动填充此字段,然后上传结果文件。
{{< /note >}}
<!--
Once the CSR is approved and the signed certificate is uploaded, run:
-->
批准 CSR 并上传签名证书后,运行:
```shell
kubectl get csr
```
<!-- The output is similar to: -->
输入类似于:
```none
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
my-svc.my-namespace 20m example.com/serving yourname@example.com <none> Approved,Issued
```
<!--
You can download the issued certificate and save it to a `server.crt` file
by running the following:
## Download the certificate and use it
Now, as the requesting user, you can download the issued certificate
and save it to a `server.crt` file by running the following:
-->
你可以通过运行以下命令下载颁发的证书并将其保存到 `server.crt` 文件中:
## 下载证书并使用它
现在,作为请求用户,你可以通过运行以下命令下载颁发的证书并将其保存到 `server.crt` 文件中:
CSR 被签署并获得批准后,你应该看到以下内容:
```shell
kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
@ -280,31 +434,74 @@ kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
```
<!--
Now you can use `server.crt` and `server-key.pem` as the keypair to start
your HTTPS server.
Now you can populate `server.crt` and `server-key.pem` in a
{{< glossary_tooltip text="Secret" term_id="secret" >}}
that you could later mount into a Pod (for example, to use with a webserver
that serves HTTPS).
-->
现在你可以将 `server.crt``server-key.pem` 作为键值对来启动 HTTPS 服务器。
现在你可以将 `server.crt``server-key.pem` 填充到
{{<glossary_tooltip text="Secret" term_id="secret" >}} 中,
稍后你可以将其挂载到 Pod 中(例如,用于提供 HTTPS 的网络服务器)。
```shell
kubectl create secret tls server --cert server.crt --key server-key.pem
```
```none
secret/server created
```
<!--
Finally, you can populate `ca.pem` into a {{< glossary_tooltip text="ConfigMap" term_id="configmap" >}}
and use it as the trust root to verify the serving certificate:
-->
最后,你可以将 `ca.pem` 填充到
{{<glossary_tooltip text="ConfigMap" term_id="configmap" >}}
并将其用作信任根来验证服务证书:
```shell
kubectl create configmap example-serving-ca --from-file ca.crt=ca.pem
```
```none
configmap/example-serving-ca created
```
<!--
## Approving Certificate Signing Requests
## Approving CertificateSigningRequests {#approving-certificate-signing-requests}
A Kubernetes administrator (with appropriate permissions) can manually approve
(or deny) Certificate Signing Requests by using the `kubectl certificate
(or deny) CertificateSigningRequests by using the `kubectl certificate
approve` and `kubectl certificate deny` commands. However if you intend
to make heavy usage of this API, you might consider writing an automated
certificates controller.
-->
## 批准证书签名请求
## 批准证书签名请求CSR {#approving-certificate-signing-requests}
Kubernetes 管理员(具有适当权限)可以使用 `kubectl certificate approve`
`kubectl certificate deny` 命令手动批准(或拒绝)证书签名请求。
`kubectl certificate deny` 命令手动批准(或拒绝)证书签名请求CSR
但是,如果你打算大量使用此 API则可以考虑编写自动化的证书控制器。
{{< caution >}}
<!--
The ability to approve CSRs decides who trusts whom within your environment. The
ability to approve CSRs should not be granted broadly or lightly.
You should make sure that you confidently understand both the verification requirements
that fall on the approver **and** the repercussions of issuing a specific certificate
before you grant the `approve` permission.
-->
批准证书 CSR 的能力决定了在你的环境中谁信任谁。
不应广泛或轻率地授予批准 CSR 的能力。
在授予 `approve` 权限之前,你应该确保自己充分了解批准人的验证要求**和**颁发特定证书的后果。
{{< /caution >}}
<!--
Whether a machine or a human using kubectl as above, the role of the approver is
Whether a machine or a human using kubectl as above, the role of the _approver_ is
to verify that the CSR satisfies two requirements:
-->
无论上述机器或人使用 kubectl批准者的作用是验证 CSR 满足如下两个要求:
无论上述机器或人使用 kubectl批准者的作用是验证 CSR 满足如下两个要求:
<!--
1. The subject of the CSR controls the private key used to sign the CSR. This
@ -325,28 +522,20 @@ to verify that the CSR satisfies two requirements:
<!--
If and only if these two requirements are met, the approver should approve
the CSR and otherwise should deny the CSR.
For more information on certificate approval and access control, read
the [Certificate Signing Requests](/docs/reference/access-authn-authz/certificate-signing-requests/)
reference page.
-->
当且仅当满足这两个要求时,审批者应该批准 CSR否则拒绝 CSR。
<!--
## A Word of Warning on the Approval Permission
The ability to approve CSRs decides who trusts who within the cluster. This
includes who the Kubernetes API trusts. The ability to approve CSRs should
not be granted broadly or lightly. The requirements of the challenge
noted in the previous section and the repercussions of issuing a specific
certificate should be fully understood before granting this permission.
-->
## 关于批准权限的警告
批准 CSR 的能力决定了群集中的信任关系。这也包括 Kubernetes API 所信任的人。
批准 CSR 的能力不能过于广泛和轻率。
在给予本许可之前,应充分了解上一节中提到的挑战和发布特定证书的后果。
有关证书批准和访问控制的更多信息,
请阅读[证书签名请求](/zh/docs/reference/access-authn-authz/certificate-signing-requests/)参考页。
<!--
## A Note to Cluster Administrators
## Configuring your cluster to provide signing
This tutorial assumes that a signer is setup to serve the certificates API. The
This page assumes that a signer is setup to serve the certificates API. The
Kubernetes controller manager provides a default implementation of a signer. To
enable it, pass the `--cluster-signing-cert-file` and
`--cluster-signing-key-file` parameters to the controller manager with paths to
@ -354,8 +543,7 @@ your Certificate Authority's keypair.
-->
## 给集群管理员的一个建议
教程假设已经为 certificates API 配置了签名者。Kubernetes 控制器管理器
提供了一个签名者的默认实现。要启用它,请为控制器管理器设置
页面假设已经为 certificates API 配置了签名者。
Kubernetes 控制器管理器提供了一个签名者的默认实现。要启用它,请为控制器管理器设置
`--cluster-signing-cert-file``--cluster-signing-key-file` 参数,
使之取值为你的证书机构的密钥对的路径。