Unit: Need a better way to update certificate.

Created on 7 Dec 2018  路  3Comments  路  Source: nginx/unit

Assume that we have listen socket bind certificate.

curl -X PUT --data-binary @bundle.pem http://.../certificates/bundle
{
    "listeners": {
        "127.0.0.1:8080": {
            "application": "wsgi-app",
            "tls": {
                "certificate": "bundle"
            }
        }
    }
}



md5-7af68ccd943a39ff44f35e837e0c2d6e



curl -X PUT --data-binary @bundle.pem http://.../certificates/bundle

Thanks.

enhancement

Most helpful comment

@hongzhidao

  1. The state directory is a blackbox. Nobody should look or touch anything inside it. All the changes must be done only using API (otherwise we will face with endless consistency problems). The content of the directory will be changed over time and may turn into binary some day. Making it readable is against the concept.
  2. One of major concepts of API configuration is that all the modifications must be atomic. From your patch it's not clear how do you revert to the previous certificate if anything goes wrong.

All 3 comments

Currently, you can do the following steps:

  1. Put a new certificate under the new name "bundle2";
  2. Switch listening socket to the new certificate (PUT "bundle2" /config/listeners/127.0.0.1:8080/tls/certificate);
  3. (Optionally) Delete the old one.

That was just easier to implement the way it works now. In the future we should make it more convenient, just in one step as you mentioned. It needs additional work.

@VBart take a look, please.

  1. Support pretty json in configure.
    Since we often look over conf.json file, it would be better to support a pretty format.
  2. Auto sends the current conf to router process if the exists cert file is updated.
diff -r aae6699f4eee src/nxt_controller.c
--- a/src/nxt_controller.c  Tue Oct 29 16:07:21 2019 +0300
+++ b/src/nxt_controller.c  Mon Nov 04 22:01:42 2019 +0800
@@ -80,6 +80,10 @@
     nxt_controller_request_t *req, nxt_str_t *path);
 static void nxt_controller_process_cert_save(nxt_task_t *task,
     nxt_port_recv_msg_t *msg, void *data);
+static void nxt_controller_process_cert_update(nxt_task_t *task,
+    nxt_port_recv_msg_t *msg, void *data);
+static void nxt_controller_process_cert_handler(nxt_task_t *task,
+    nxt_port_recv_msg_t *msg, void *data);
 static nxt_bool_t nxt_controller_cert_in_use(nxt_str_t *name);
 #endif
 static void nxt_controller_conf_handler(nxt_task_t *task,
@@ -353,12 +357,13 @@
 nxt_controller_conf_send(nxt_task_t *task, nxt_conf_value_t *conf,
     nxt_port_rpc_handler_t handler, void *data)
 {
-    size_t         size;
-    uint32_t       stream;
-    nxt_int_t      rc;
-    nxt_buf_t      *b;
-    nxt_port_t     *router_port, *controller_port;
-    nxt_runtime_t  *rt;
+    size_t                  size;
+    uint32_t                stream;
+    nxt_int_t               rc;
+    nxt_buf_t               *b;
+    nxt_port_t              *router_port, *controller_port;
+    nxt_runtime_t           *rt;
+    nxt_conf_json_pretty_t  pretty;

     rt = task->thread->runtime;

@@ -370,14 +375,18 @@

     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];

-    size = nxt_conf_json_length(conf, NULL);
+    nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
+
+    size = nxt_conf_json_length(conf, &pretty);

     b = nxt_port_mmap_get_buf(task, router_port, size);
     if (nxt_slow_path(b == NULL)) {
         return NXT_ERROR;
     }

-    b->mem.free = nxt_conf_json_print(b->mem.free, conf, NULL);
+    nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
+
+    b->mem.free = nxt_conf_json_print(b->mem.free, conf, &pretty);

     stream = nxt_port_rpc_register_handler(task, controller_port,
                                            handler, handler,
@@ -1281,7 +1290,9 @@
     if (nxt_str_eq(&req->parser.method, "PUT", 3)) {
         value = nxt_cert_info_get(&name);
         if (value != NULL) {
-            goto exists_cert;
+            nxt_cert_store_get(task, &name, c->mem_pool,
+                               nxt_controller_process_cert_update, req);
+            return;
         }

         cert = nxt_cert_mem(task, &c->read->mem);
@@ -1346,15 +1357,6 @@
     nxt_controller_response(task, req, &resp);
     return;

-exists_cert:
-
-    resp.status = 400;
-    resp.title = (u_char *) "Certificate already exists.";
-    resp.offset = -1;
-
-    nxt_controller_response(task, req, &resp);
-    return;
-
 cert_in_use:

     resp.status = 400;
@@ -1394,6 +1396,72 @@


 static void
+nxt_controller_process_cert_update(nxt_task_t *task, nxt_port_recv_msg_t *msg,
+    void *data)
+{
+    nxt_int_t                 ret;
+    nxt_conn_t                *c;
+    nxt_buf_mem_t             *mbuf;
+    nxt_controller_request_t  *req;
+    nxt_controller_response_t  resp;
+
+    req = data;
+
+    if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
+        goto fail;
+    }
+
+    c = req->conn;
+
+    mbuf = &c->read->mem;
+
+    nxt_fd_write(msg->fd, mbuf->pos, nxt_buf_mem_used_size(mbuf));
+
+    nxt_fd_close(msg->fd);
+
+    ret = nxt_controller_conf_send(task, nxt_controller_conf.root,
+                                   nxt_controller_process_cert_handler, req);
+
+    if (nxt_fast_path(ret == NXT_OK)) {
+        return;
+    }
+
+fail:
+
+    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
+
+    resp.status = 500;
+    resp.title = (u_char *) "Failed to store certificate.";
+
+    nxt_controller_response(task, req, &resp);
+}
+
+
+static void
+nxt_controller_process_cert_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
+    void *data)
+{
+    nxt_controller_request_t   *req;
+    nxt_controller_response_t  resp;
+
+    req = data;
+
+    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
+
+    if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) {
+        resp.status = 500;
+        resp.title = (u_char *) "Failed to store certificate.";
+
+    } else {
+        resp.status = 200;
+        resp.title = (u_char *) "Certificate chain uploaded.";
+    }
+
+    nxt_controller_response(task, req, &resp);
+}
+
+
+static void
 nxt_controller_process_cert_save(nxt_task_t *task, nxt_port_recv_msg_t *msg,
     void *data)
 {

@hongzhidao

  1. The state directory is a blackbox. Nobody should look or touch anything inside it. All the changes must be done only using API (otherwise we will face with endless consistency problems). The content of the directory will be changed over time and may turn into binary some day. Making it readable is against the concept.
  2. One of major concepts of API configuration is that all the modifications must be atomic. From your patch it's not clear how do you revert to the previous certificate if anything goes wrong.
Was this page helpful?
0 / 5 - 0 ratings