Merge pull request #31591 from liggitt/tls-example
Update TLS doc to use example signer for arbitrary https server
This commit is contained in:
@@ -76,16 +76,11 @@ cat <<EOF | cfssl genkey - | cfssljson -bare server
|
|||||||
"192.0.2.24",
|
"192.0.2.24",
|
||||||
"10.0.34.2"
|
"10.0.34.2"
|
||||||
],
|
],
|
||||||
"CN": "system:node:my-pod.my-namespace.pod.cluster.local",
|
"CN": "my-pod.my-namespace.pod.cluster.local",
|
||||||
"key": {
|
"key": {
|
||||||
"algo": "ecdsa",
|
"algo": "ecdsa",
|
||||||
"size": 256
|
"size": 256
|
||||||
},
|
}
|
||||||
"names": [
|
|
||||||
{
|
|
||||||
"O": "system:nodes"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
@@ -93,13 +88,13 @@ EOF
|
|||||||
Where `192.0.2.24` is the service's cluster IP,
|
Where `192.0.2.24` is the service's cluster IP,
|
||||||
`my-svc.my-namespace.svc.cluster.local` is the service's DNS name,
|
`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`
|
`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:
|
||||||
|
|
||||||
```
|
```
|
||||||
2017/03/21 06:48:17 [INFO] generate received request
|
2022/02/01 11:45:32 [INFO] generate received request
|
||||||
2017/03/21 06:48:17 [INFO] received CSR
|
2022/02/01 11:45:32 [INFO] received CSR
|
||||||
2017/03/21 06:48:17 [INFO] generating key: ecdsa-256
|
2022/02/01 11:45:32 [INFO] generating key: ecdsa-256
|
||||||
2017/03/21 06:48:17 [INFO] encoded CSR
|
2022/02/01 11:45:32 [INFO] encoded CSR
|
||||||
```
|
```
|
||||||
|
|
||||||
This command generates two files; it generates `server.csr` containing the PEM
|
This command generates two files; it generates `server.csr` containing the PEM
|
||||||
@@ -120,7 +115,7 @@ metadata:
|
|||||||
name: my-svc.my-namespace
|
name: my-svc.my-namespace
|
||||||
spec:
|
spec:
|
||||||
request: $(cat server.csr | base64 | tr -d '\n')
|
request: $(cat server.csr | base64 | tr -d '\n')
|
||||||
signerName: kubernetes.io/kubelet-serving
|
signerName: example.com/serving
|
||||||
usages:
|
usages:
|
||||||
- digital signature
|
- digital signature
|
||||||
- key encipherment
|
- key encipherment
|
||||||
@@ -131,7 +126,7 @@ EOF
|
|||||||
Notice that the `server.csr` file created in step 1 is base64 encoded
|
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. We are also requesting a
|
||||||
certificate with the "digital signature", "key encipherment", and "server
|
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.
|
A specific `signerName` must be requested.
|
||||||
View documentation for [supported signer names](/docs/reference/access-authn-authz/certificate-signing-requests/#signers)
|
View documentation for [supported signer names](/docs/reference/access-authn-authz/certificate-signing-requests/#signers)
|
||||||
for more information.
|
for more information.
|
||||||
@@ -147,14 +142,16 @@ kubectl describe csr my-svc.my-namespace
|
|||||||
Name: my-svc.my-namespace
|
Name: my-svc.my-namespace
|
||||||
Labels: <none>
|
Labels: <none>
|
||||||
Annotations: <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
|
Requesting User: yourname@example.com
|
||||||
|
Signer: example.com/serving
|
||||||
Status: Pending
|
Status: Pending
|
||||||
Subject:
|
Subject:
|
||||||
Common Name: my-svc.my-namespace.svc.cluster.local
|
Common Name: my-pod.my-namespace.pod.cluster.local
|
||||||
Serial Number:
|
Serial Number:
|
||||||
Subject Alternative Names:
|
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
|
IP Addresses: 192.0.2.24
|
||||||
10.0.34.2
|
10.0.34.2
|
||||||
Events: <none>
|
Events: <none>
|
||||||
@@ -175,30 +172,136 @@ kubectl certificate approve my-svc.my-namespace
|
|||||||
certificatesigningrequest.certificates.k8s.io/my-svc.my-namespace approved
|
certificatesigningrequest.certificates.k8s.io/my-svc.my-namespace approved
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You should now see the following:
|
||||||
## Download the Certificate and Use It
|
|
||||||
|
|
||||||
Once the CSR is signed and approved you should see the following:
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get csr
|
kubectl get csr
|
||||||
```
|
```
|
||||||
|
|
||||||
```none
|
```none
|
||||||
NAME AGE REQUESTOR CONDITION
|
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
|
||||||
my-svc.my-namespace 10m yourname@example.com Approved,Issued
|
my-svc.my-namespace 10m example.com/serving yourname@example.com <none> Approved
|
||||||
```
|
```
|
||||||
|
|
||||||
You can download the issued certificate and save it to a `server.crt` file
|
This means the certificate request has been approved and is waiting for the
|
||||||
by running the following:
|
requested signer to sign it.
|
||||||
|
|
||||||
|
## 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 Certificate Signing Request 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.
|
||||||
|
|
||||||
|
### Create a Certificate Authority
|
||||||
|
|
||||||
|
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 the 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`).
|
||||||
|
|
||||||
|
### 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:
|
||||||
|
|
||||||
|
```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 the 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`.
|
||||||
|
|
||||||
|
### Upload the Signed Certificate
|
||||||
|
|
||||||
|
Finally, populate the signed certificate in the API object's status:
|
||||||
|
|
||||||
|
```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.
|
||||||
|
{{< /note >}}
|
||||||
|
|
||||||
|
Once the CSR is approved and the signed certificate is uploaded you should see the following:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get csr
|
||||||
|
```
|
||||||
|
|
||||||
|
```none
|
||||||
|
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
|
||||||
|
my-svc.my-namespace 20m example.com/serving yourname@example.com <none> Approved,Issued
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
|
kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
|
||||||
| base64 --decode > server.crt
|
| base64 --decode > server.crt
|
||||||
```
|
```
|
||||||
|
|
||||||
Now you can use `server.crt` and `server-key.pem` as the keypair to start
|
Now you can populate `server.crt` and `server-key.pem` in a secret and mount
|
||||||
your HTTPS server.
|
it into a pod to use as the keypair to start your HTTPS server:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl create secret tls server --cert server.crt --key server-key.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
```none
|
||||||
|
secret/server created
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, you can populate `ca.pem` in a configmap and use it as the trust root
|
||||||
|
to verify the serving certificate:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl create configmap example-serving-ca --from-file ca.crt=ca.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
```none
|
||||||
|
configmap/example-serving-ca created
|
||||||
|
```
|
||||||
|
|
||||||
## Approving Certificate Signing Requests
|
## Approving Certificate Signing Requests
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"signing": {
|
||||||
|
"default": {
|
||||||
|
"usages": [
|
||||||
|
"digital signature",
|
||||||
|
"key encipherment",
|
||||||
|
"server auth"
|
||||||
|
],
|
||||||
|
"expiry": "876000h",
|
||||||
|
"ca_constraint": {
|
||||||
|
"is_ca": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user