github.com/joelanford/operator-sdk@v0.8.2/doc/proposals/tls-utilities.md (about)

     1  # TLS Utilities proposal
     2  
     3  ## Background:
     4  
     5  A typical workflow of an operator that is written using the Operator-SDK involves watching a Custom Resource (CR), which specifies the desired state of the cluster, and making changes to the current state of the cluster to achieve the desired state.
     6  
     7  Each user specified CR represents a self contained system. Based on this, we can assume that any TLS assets generated are specific to each system which then is also specific to the corresponding CR.
     8  
     9  Based on the above assumption, we want to design a TLS utility pkg that helps generate TLS assets and ties them to a specific CR.
    10  
    11  ## Goals:
    12  
    13  To provide TLS utilities for operator developers to create self signed Certificate Authority (CA) and the TLS encryption keys along with the signed certs. This will enable the operator to setup TLS assets for the application so that all the communication within it is secure.
    14  
    15  ## Details:
    16  
    17  We will break down the TLS workflow into the following steps:
    18  
    19  1. Generate a Certificate Authority (CA): A CA is a centralized trusted third party that signs the certificates. We need to generate a CA key and CA Certificate to get started. If the users want to provide their own CA, we can add an option to do so. The generated CA certificate can be saved in a ConfigMap as follows:
    20  
    21  	Inputs:
    22  
    23  	* CR-kind
    24  	* CR-name
    25  	* namespace
    26  
    27  	Outputs:
    28  
    29          * A ConfigMap that contains the CA Cert:
    30  
    31  	```
    32  	kind: ConfigMap
    33  	apiVersion: v1
    34  	metadata:
    35  	name: <crd-kind>-<crd-name>-ca
    36  	namespace: <ns>
    37  	data:
    38  	ca.crt: ...
    39              ```
    40          * A secret that contains the CA key:
    41  
    42             ```
    43  	kind: Secret
    44  	apiVersion: v1
    45  	metadata:
    46  	name: <cr-kind>-<cr-name>-ca
    47  	namespace: <ns>
    48  	data:
    49  	ca.key: ...
    50  	```
    51  
    52  2. Verify the CA certificate: The newly generated CA certificate in ConfigMap should be validated i.e. the digital signature should be checked, the expiry, activation dates and validity period should be checked, etc.
    53  
    54  3. Generate Server or Client Certificate: We assume that the components inside an application communicate through a service. Therefore, we generate a TLS private key and certificate for that service.
    55  
    56  	Inputs:
    57  
    58  	* CR-kind
    59  	* CR-name
    60  	* Namespace
    61  	* Previously generated CA key and Certificate
    62  
    63  	Options:
    64  
    65  	* Key usage: (Server, Client or Both) If Server, needs svc obj (cluster.local can be different). If client, needs CN and possible org.
    66  	* Option to specify signature configuration policy i.e Signing Profile for the certificate.
    67  
    68          Outputs:
    69  
    70  	* A Secret containing Private Key and Server/Client Certificate signed by the CA:
    71  
    72  	```
    73  	kind: Secret
    74  	apiVersion: v1
    75  	metadata:
    76  	 name: <cr-kind>-<cr-name>-<CertName>
    77  	 namespace: <ns>
    78  	data:
    79  	 tls.crt: ...
    80  	 tls.key: …
    81  	type: kubernetes.io/tls
    82  	```
    83  
    84  4. Verify Server or Client Certificate: The newly generated client/server certificate in should be validated i.e. the digital signature should be checked, the expiry, activation dates and validity period should be checked, certificate chain should be verified etc
    85  
    86  
    87  5. Use CA configmap and TLS secret in the necessary deployment/pod object.
    88  
    89  ## Implementation:
    90  
    91  Have a certificate configuration object which will contain all the input arguments required to generate a server/client certificate.
    92  
    93  ```
    94  // CertConfig configures the Cert generation.
    95  type CertConfig struct {
    96  	// CertName is the name of the cert.
    97  	CertName string
    98  	// Optional CertType. Server, client or both; defaults to both.
    99  	CertType CertType
   100  	// CommonName is the common name of the cert
   101  	CommonName string
   102  	// Organization is Organization of the cert
   103  	Organization []string
   104  	// Optional CA Key, if user wants to provide custom CA
   105  	CAKey string
   106  	// Optional CA Certificate, if user wants to provide custom CA
   107  	CACert string
   108  }
   109  ```
   110  
   111  Have a method which will generate a secret that contains a newly created TLS Private key and Certificate for the given service. A unique CA is also generated by default to sign the Certificate if a prior CA certificate is not preset for the user specified CR. If the user wants to use a custom CA, it can be specified in the `CertConfig` object. The function signature of the method is as follows:
   112  
   113  ```
   114  func GenerateCert(cr runtime.Object, service *v1.Service, config *CertConfig) (*v1.Secret, *v1.ConfigMap, *v1.Secret, error)
   115  
   116  ```
   117  
   118  Please note that the `GenerateCert` method cannot be used to generate TLS assets for a service of type [`ExternalName`](https://kubernetes.io/docs/concepts/services-networking/service/#externalname). This is because in the current design the fully qualified domain name (FQDN) of the Service object is used as the SAN for the certificate by default. Currently we do not have a way to customize the SAN value, we will add a field in `CertConfig` for this purpose later on.
   119  
   120  The `GenerateCert` method can be used in the operator handler function to set up TLS for the desired application
   121  
   122  ```
   123  // ../pkg/stub/handler.go
   124  func (h *Handler) Handle(ctx types.Context, event types.Event) error {
   125  	switch crd := event.Object.(type) {
   126  	case *api.AppService:
   127  		cfg := CertConfig{
   128  			CertName: "server1",
   129  		}
   130  		s := v1.Service{...}
   131  		tlsCertSecret, caCertConfigMap, caKeySecret, err := GenerateCert(crd, s, cfg)
   132  		if err != nil {
   133  			return err
   134  		}
   135  		// use the newly generated TLS secret in a deployment manifest to mount it as volume.
   136  		...
   137  	}
   138  }
   139  ```
   140  ## Workflow:
   141  
   142  To understand the implementation details more clearly let us run through an example operator and how it can make use of the TLS utility package:
   143  
   144  Let us take the Vault Operator as an example. The Vault operator deploys and manages Vault clusters on Kubernetes. The following workflow is a step by step guide of how the vault operator can make use of the TLS utility package described above:
   145  
   146  1. Create the Vault CR using [`kubectl create`](https://github.com/coreos/vault-operator/blob/master/example/vault_crd.yaml)
   147  2. Modify the operator handler to generate the necessary vault server TLS assets:
   148  	1. Populate the struct `CertConfig` with required values which specify the server certificate.
   149  	2. Call the `GenerateCert` method which will generate and return a secret that contains a newly created TLS Private key and Certificate for the Vault server. This Certificate will be signed by a custom CA or a newly generated CA depending on the configuration in `CertConfig`.
   150  3. The operator is responsible for creating a service and deployment manifests for the application the user wishes to run. The deployment manifests will contain the TLS assets generated in step 2 as Volume mounts.
   151  
   152  ## Q&A:
   153  
   154  1. What happens after the CA certificate expires?
   155     Once the CA certificate expires, all certificates signed by the CA become invalid.
   156  
   157  ## Future Plans:
   158  
   159  1. Maintenance and rotation of these TLS certificates: Setting a certificate rotation policy from the start will protect you against the usual key mismanagement or leaking that is bound to happen over long periods of time. This is often overlooked and never-expiring tokens are shared between administrators for convenience reasons. To start off simple, we can provide a simple command line tool `--rotate-certificates` that will perform a rotation for a specific certificate.
   160  
   161  2. Consider having a signer server and a client agent in our TLS utilities package. The server will handle HTTP requests and responses. When it receives a CSR approval requests from the client agent it attempts to sign it. If successful, the approved CSR, which contains the signed certificate, is returned to the agent. This server-client mechanism will eliminate the need to copy around certs.