From 28a1283dd4c70d3ff1604bec21b718a7e2796ad1 Mon Sep 17 00:00:00 2001 From: Lukasz Nowak <luke@nexedi.com> Date: Thu, 15 Nov 2018 17:21:38 +0100 Subject: [PATCH] caddy-frontend: Implement AIKC AIKC - Automatic Internal Kedifa's Caucase CSR signing, which can be triggered by option automatic-internal-kedifa-caucase-csr. It signs all CSR which match csr_id and certificate from the nodes which needs them. --- software/caddy-frontend/buildout.hash.cfg | 6 +- .../instance-apache-replicate.cfg.in | 129 +++++++++++++++++- .../instance-caddy-input-schema.json | 10 ++ .../caddy-frontend/instance-kedifa.cfg.in | 2 +- software/caddy-frontend/instance.cfg.in | 1 + 5 files changed, 141 insertions(+), 7 deletions(-) diff --git a/software/caddy-frontend/buildout.hash.cfg b/software/caddy-frontend/buildout.hash.cfg index 3fde8cfdb..af61748f1 100644 --- a/software/caddy-frontend/buildout.hash.cfg +++ b/software/caddy-frontend/buildout.hash.cfg @@ -14,7 +14,7 @@ # not need these here). [template] filename = instance.cfg.in -md5sum = 733ef269151e9884e44174bb4dc9c6ea +md5sum = ffaf426c68b2f7a35558bf187b5981b7 [template-common] filename = instance-common.cfg.in @@ -26,7 +26,7 @@ md5sum = b3275d8203b36506ea0f2f9c12f86399 [template-apache-replicate] filename = instance-apache-replicate.cfg.in -md5sum = ece5f1c068a3096eef6bcc8deaf8bbe2 +md5sum = ab77522560589fc315ddb6c8d28c4015 [template-slave-list] filename = templates/apache-custom-slave-list.cfg.in @@ -118,4 +118,4 @@ md5sum = 38792c2dceae38ab411592ec36fff6a8 [template-kedifa] filename = instance-kedifa.cfg.in -md5sum = bffe1624132dbf42a788ce8ae5bd7cab +md5sum = 66de9edcd66447271424be3d92c2cb90 diff --git a/software/caddy-frontend/instance-apache-replicate.cfg.in b/software/caddy-frontend/instance-apache-replicate.cfg.in index 0f190f5b5..470782a33 100644 --- a/software/caddy-frontend/instance-apache-replicate.cfg.in +++ b/software/caddy-frontend/instance-apache-replicate.cfg.in @@ -1,5 +1,6 @@ {% if slap_software_type in software_type %} - +{%- set TRUE_VALUES = ['y', 'yes', '1', 'true'] -%} +{% set aikc_enabled = slapparameter_dict.get('automatic-internal-kedifa-caucase-csr', '').lower() in TRUE_VALUES %} [jinja2-template-base] recipe = slapos.recipe.template:jinja2 rendered = ${buildout:directory}/${:filename} @@ -199,14 +200,16 @@ rejected-slave-amount = {{ rejected_slave_dict | length }} rejected-slave-dict = {{ dumps(json_module.dumps(rejected_slave_dict)) }} master-key-upload-url = ${request-kedifa:connection-master-key-upload-url} master-key-generate-auth-url = ${request-kedifa:connection-master-key-generate-auth-url} +kedifa-caucase-url = ${request-kedifa:connection-caucase-url} +{% if not aikc_enabled %} kedifa-csr_id-url = ${request-kedifa:connection-csr_id-url} kedifa-csr_id-certificate = ${request-kedifa:connection-csr_id-certificate} -kedifa-caucase-url = ${request-kedifa:connection-caucase-url} {% for frontend in frontend_list %} {% set section_part = '${request-' + frontend %} {{ frontend }}-csr_id-url = {{ section_part }}:connection-csr_id-url} -{{ frontend }}-csr_ud-certificate = {{ section_part }}:connection-csr_id-certificate} +{{ frontend }}-csr_id-certificate = {{ section_part }}:connection-csr_id-certificate} {% endfor %} +{% endif %} #---------------------------- #-- @@ -286,6 +289,126 @@ monitor-url-list += {{ ' ${' + frontend + ':connection-monitor-base-url}' }} {% endfor %} +{% if aikc_enabled %} +[directory] +recipe = slapos.cookbook:mkdirectory + +bin = ${buildout:directory}/bin/ +srv = ${buildout:directory}/srv/ +aikc = ${:srv}/aikc + +[aikc-config] +caucase-url = ${request-kedifa:connection-caucase-url} + +csr = ${directory:aikc}/csr.pem +key = ${directory:aikc}/key.pem +ca-certificate = ${directory:aikc}/cas-ca-certificate.pem +crl = ${directory:aikc}/crl.pem +user-ca-certificate = ${directory:aikc}/user-ca-certificate.pem +user-crl = ${directory:aikc}/user-crl.pem +user-created = ${directory:aikc}/user-created +csr_id = ${directory:aikc}/csr_id + +[aikc-user-csr] +recipe = plone.recipe.command +organization = {{ cluster_identification }} +organizational_unit = Automatic Internal Kedifa Caucase CSR +command = + if [ ! -f ${:csr} ] && [ ! -f ${:key} ] ; then + {{ parameter_dict['openssl'] }} req -new -sha256 \ + -newkey rsa:2048 -nodes -keyout ${:key} \ + -subj "/O=${:organization}/OU=${:organizational_unit}" \ + -out ${:csr} + fi +update-command = ${:command} +csr = ${aikc-config:csr} +key = ${aikc-config:key} +stop-on-error = True + + +[aikc-caucase-wrapper] +{# jinja2 instead of wrapper is used with context to remove py'u' #} +recipe = slapos.recipe.template:jinja2 +context = + key caucase_url aikc-config:caucase-url +template = inline:#!{{ parameter_dict['dash'] }}/bin/dash + exec {{ parameter_dict['bin_directory'] }}/caucase \ +{# raw block to use context #} +{% raw %} + --ca-url {{ caucase_url }} \ +{% endraw %} + --ca-crt ${aikc-config:ca-certificate} \ + --user-ca-crt ${aikc-config:user-ca-certificate} \ + --user-crl ${aikc-config:user-crl} \ + --crl ${aikc-config:crl} \ + "$@" + +rendered = ${directory:bin}/aikc-caucase-wrapper +mode = 0700 + +{% do part_list.append('aikc-create-user') %} +[aikc-create-user] +recipe = plone.recipe.command +stop-on-error = True +update-command = ${:command} +command = + if ! [ -f ${aikc-config:user-created} ] ; then + ${aikc-caucase-wrapper:rendered} --mode user --send-csr ${aikc-user-csr:csr} > ${aikc-config:csr_id} || exit 1 + cut -d ' ' -f 1 ${aikc-config:csr_id} || exit 1 + csr_id=`cut -d ' ' -f 1 ${aikc-config:csr_id}` + sleep 1 + ${aikc-caucase-wrapper:rendered} --mode user --get-crt $csr_id ${aikc-config:key} || exit 1 + touch ${aikc-config:user-created} + fi + +[aikc-check-certificate] +recipe = slapos.recipe.template:jinja2 +rendered = ${directory:bin}/aikc-check-certificate +template = inline: + import sys + import ssl + import urlparse + certificate = sys.argv[2] + parsed = urlparse.urlparse(sys.argv[1]) + got_certificate = ssl.get_server_certificate((parsed.hostname, parsed.port)) + sys.exit(0) if certificate.strip() == got_certificate.strip() else sys.exit(1) + +{% for csr in frontend_list + ['kedifa'] %} +[aikc-{{ csr }}-wrapper] +{# jinja2 instead of wrapper is used with context to remove py'u' #} +recipe = slapos.recipe.template:jinja2 +context = + key csr_id_url request-{{ csr }}:connection-csr_id-url + key csr_id_certificate request-{{ csr }}:connection-csr_id-certificate +template = inline:#!{{ parameter_dict['dash'] }}/bin/dash + test -f ${directory:aikc}/{{ csr }}-done && exit 0 + ${buildout:executable} ${aikc-check-certificate:rendered} \ +{# raw block to use context #} +{% raw %} + {{ csr_id_url }} \ + """{{ csr_id_certificate }}""" +{% endraw %} + if [ $? = 0 ]; then + csr_id=`{{ parameter_dict['curl'] }}/bin/curl -s -k -g \ +{% raw %} + {{ csr_id_url }} \ +{% endraw %} + ` || exit 1 + ${aikc-caucase-wrapper:rendered} --user-key ${aikc-config:key} --sign-csr $csr_id && touch ${directory:aikc}/{{ csr }}-done + fi +rendered = ${directory:bin}/aikc-{{ csr }}-wrapper +mode = 0700 + +{% do part_list.append('aikc-%s' % (csr,)) %} +[aikc-{{ csr }}] +recipe = plone.recipe.command +stop-on-error = True +command = + ${aikc-{{ csr }}-wrapper:rendered} +update-command = ${:command} +{% endfor %} +{% endif %} + [buildout] extends = {{ common_profile }} diff --git a/software/caddy-frontend/instance-caddy-input-schema.json b/software/caddy-frontend/instance-caddy-input-schema.json index 8e976dd0b..d8f795129 100644 --- a/software/caddy-frontend/instance-caddy-input-schema.json +++ b/software/caddy-frontend/instance-caddy-input-schema.json @@ -80,6 +80,16 @@ "description": "How often Caddy will try to establish connection with a backend during proxy-try-duration. More info in https://caddyserver.com/docs/proxy try_interval", "title": "Interval in milliseconds of tries during proxy-try-duration", "type": "integer" + }, + "automatic-internal-kedifa-caucase-csr": { + "default": "false", + "description": "Automatically signs CSRs sent to KeDiFa's caucase, based on csr_id and matching certificate.", + "enum": [ + "true", + "false" + ], + "title": "Automatic Internal KeDiFa's Caucase CSR", + "type": "string" } }, "title": "Input Parameters", diff --git a/software/caddy-frontend/instance-kedifa.cfg.in b/software/caddy-frontend/instance-kedifa.cfg.in index 1826fdff4..07d61a837 100644 --- a/software/caddy-frontend/instance-kedifa.cfg.in +++ b/software/caddy-frontend/instance-kedifa.cfg.in @@ -197,7 +197,7 @@ port = {{ instance_parameter['configuration.kedifa_port'] }} db = ${directory:kedifa}/kedifa.sqlite certificate = ${directory:etc-kedifa}/certificate.pem key = ${:certificate} -ca-certificate = ${directory:etc-kedifa}/cas-ca-certificate.pem +ca-certificate = ${directory:etc-kedifa}/ca-certificate.pem crl = ${directory:etc-kedifa}/crl.pem template-csr = ${directory:etc-kedifa}/template-csr.pem pidfile = ${directory:run}/kedifa.pid diff --git a/software/caddy-frontend/instance.cfg.in b/software/caddy-frontend/instance.cfg.in index 4e839e151..4784fafe1 100644 --- a/software/caddy-frontend/instance.cfg.in +++ b/software/caddy-frontend/instance.cfg.in @@ -65,6 +65,7 @@ extra-context = raw software_type RootSoftwareInstance-default-custom-personal-replicate raw template_monitor {{ monitor2_template }} raw common_profile {{ common_profile }} + section parameter_dict dynamic-template-caddy-frontend-parameters [dynamic-template-kedifa] < = jinja2-template-base -- 2.30.9