summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Tankersley <george.tankersley@coreos.com>2016-02-01 13:41:40 -0800
committerGeorge Tankersley <george.tankersley@coreos.com>2016-02-01 13:56:07 -0800
commit7c97ddefc823ace427ce21e9ee6604a5d492d3e8 (patch)
tree2840073555319b910fdbd216509e5a4760175365
parenta7ffad51f9353ea1d9d8304c4bd4da31073aa94c (diff)
Add proposal for kubelet TLS bootstrap
-rw-r--r--kubelet-tls-bootstrap.md183
1 files changed, 183 insertions, 0 deletions
diff --git a/kubelet-tls-bootstrap.md b/kubelet-tls-bootstrap.md
new file mode 100644
index 00000000..67a16986
--- /dev/null
+++ b/kubelet-tls-bootstrap.md
@@ -0,0 +1,183 @@
+# Kubelet TLS bootstrap
+Author: George Tankersley (george.tankersley@coreos.com)
+
+## Preface
+This document describes a method for a kubelet to bootstrap itself
+into a TLS-secured cluster. Crucially, it automates the provision and
+distribution of signed certificates.
+
+## Overview
+When a kubelet runs for the first time, it must be given TLS assets
+or generate them itself. In the first case, this is a burden on the cluster
+admin and a significant logistical barrier to secure Kubernetes rollouts. In
+the second, the kubelet must self-sign its certificate and forfeits many of the
+advantages of a PKI system. Instead, we propose that the kubelet generate a
+private key and a CSR for submission to a cluster-level certificate signing
+process.
+
+## Preliminaries
+We assume the existence of a functioning control plane. The
+apiserver should be configured for TLS initially or possess the ability to
+generate valid TLS credentials for itself. If secret information is passed in
+the request (e.g. auth tokens supplied with the request or included in
+ExtraInfo) then all communications from the node to the apiserver must take
+place over a verified TLS connection.
+
+Each node is additionally provisioned with the following information:
+
+1. Location of the apiserver
+2. Any CA certificates necessary to trust the apiserver's TLS certificate
+3. Access tokens (if needed) to communicate with the CSR endpoint
+
+These should not change often and are thus simple to include in a static
+provisioning script.
+
+## API Changes
+### CertificateSigningRequest Object
+We introduce a new API object to represent PKCS#10 certificate signing
+requests. It will be accessible under:
+
+`/api/vX/certificaterequests/mycsr`
+
+It will have the following structure:
+
+```go
+// Describes a certificate signing request
+type CertificateSigningRequest struct {
+ api.TypeMeta `json:",inline"`
+ api.ObjectMeta `json:"metadata,omitempty"`
+
+ // Specifies the behavior of the CSR
+ Spec CertificateSigningRequestSpec
+
+ // Most recently observed status of the CSR
+ Status CertificateSigningRequestStatus
+}
+
+type CertificateSigningRequestSpec struct {
+ // Raw PKCS#10 CSR data
+ CertificateRequest []byte
+
+ // Fingerprint of the public key that signed the CSR
+ Fingerprint string
+
+ // Subject fields from the CSR
+ Subject pkix.Name
+
+ // DNS SANs from the CSR
+ Hostnames []string
+
+ // IP SANs from the CSR
+ IPAddresses []string
+
+ // Extra information the node wishes to send with the request
+ ExtraInfo []string
+}
+
+type CertificateSigningRequestStatus struct {
+ // Indicates whether CSR has a response yet. Default is Unknown. Status
+ // is True for approval and False for rejections.
+ Status api.ConditionStatus
+
+ // If CSR was rejected, these contain the reason why (if any was supplied).
+ Reason string
+ Message string
+
+ // If CSR was approved, this contains the issued certificate.
+ Certificate []byte
+}
+```
+
+We also introduce CertificateSigningRequestList to allow listing all the CSRs in the cluster:
+
+```go
+type CertificateSigningRequestList struct {
+ api.TypeMeta
+ api.ListMeta
+
+ Items []CertificateSigningRequest
+}
+```
+
+## Certificate Request Process
+
+### Node intialization
+When the kubelet executes it checks a location on disk for TLS assets
+(currently `/var/run/kubernetes/kubelet.{key,crt}` by default). If it finds
+them, it proceeds. If there are no TLS assets, the kubelet generates a keypair
+and self-signed certificate. We propose the following optional fallback behavior:
+
+1. Generate a keypair
+2. Generate a CSR for that keypair with CN set to the hostname (or
+ `--hostname-override` value) and DNS/IP SANs supplied with whatever values
+ the host knows for itself.
+3. Post the CSR to the CSR API endpoint.
+4. Set a watch on the CSR object to be notified of approval or rejection.
+
+### Controller response
+The apiserver must first validate the signature on the raw CSR data and reject
+requests featuring invalid CSRs. It then persists the
+CertificateSigningRequests and exposes the List of all CSRs for an
+administrator to approve or reject. The apiserver should watch for updates the
+Status field of any CertificateSigningRequest. When a CSR is approved
+(signified by Status changing from Unknown to True) the apiserver should
+generate and sign the certificate, then update the
+CertificateSigningRequestStatus with the new data.
+
+### Manual CSR approval
+An administrator using `kubectl` or another API client can query the
+CertificateSigningRequestList and update the status of
+CertificateSigningRequests. The default Status is Unknown, indicating that
+there has been no decision so fare. A Status of True indicates that the admin
+has approved the request and the apiserver should issue the certificate. A
+Status of False indicates that the admin has denied the request. An admin may
+also supply Reason and Message fields to explain the rejection.
+
+## kube-apiserver support (CA assets)
+So that the apiserver can handle certificate issuance on its own, it will need
+access to CA signing assets. This could be as simple as a private key and a
+config file or as complex as a PKCS#11 client and supplementary policy system.
+For now, we will add flags for a signing key, a certificate, and a basic config
+file.
+
+## kubectl support
+To support manual CSR inspection and approval, we will add support for listing,
+inspecting, and approving/rejecting CertificateSigningRequests to kubectl. The
+interface will be similar to
+[salt-key](https://docs.saltstack.com/en/latest/ref/cli/salt-key.html).
+
+Specifically, the admin will have the ability to retrieve the full list of
+active CSRs, inspect their contents, and set their statuses to one of:
+
+1. **approved** if the apiserver should issue the cert
+2. **rejected** if the apiserver should not issue the cert
+
+The suggested commands are `kubectl get certificates`, `kubectl approve <csr>`
+and `kubectl reject <csr>`. For the reject subcommand, the admin will also be
+able to supply Reason and Message fields via additional flags.
+
+## Security Considerations
+
+### Endpoint Access Control
+The ability to post CSRs to the signing endpoint should be controlled. As a
+simple solution we propose that each node be provisioned with an auth token
+(possibly static across the cluster) that is scoped via ABAC to only allow
+access to the CSR endpoint.
+
+### Expiration & Revocation
+The node is responsible for monitoring its own certificate expiration date.
+When the certificate is close to expiration, the kubelet should begin repeating
+this flow until it successfully obtains a new certificate. If the expiring
+certificate has not been revoked then it may do so using the same keypair
+unless the cluster policy (see "Future Work") requires fresh keys.
+
+Revocation is for the most part an unhandled problem in Go, requiring each
+application to produce its own logic around a variety of parsing functions. For
+now, our suggested best practice is to issue only short-lived certificates. In
+the future it may make sense to add CRL support to the apiserver's client cert
+auth.
+
+## Future Work
+- revocation UI in kubectl and CRL support at the apiserver
+- supplemental policy (e.g. cluster CA only issues 30-day certs for hostnames *.k8s.example.com, each new cert must have fresh keys, ...)
+- fully automated provisioning (using a handshake protocol or external list of authorized machines)