Commit bb390b40 by Vincent Pelletier Committed by Łukasz Nowak

stack/caucase,stack/erp5,software/caucase: Update for caucase 0.9.5

Notes

stack/erp5

 * The service-auto-approve-amount to default is set to 1, in order that the
   only needed service is automatically approved.  As caucase is accessed
   internally (on local IPv4) only partitions on the same server will access
   caucase.
1 parent b25a0cf0
# THIS IS NOT A BUILDOUT FILE, despite purposedly using a compatible syntax.
# The only allowed lines here are (regexes):
# - "^#" comments, copied verbatim
# - "^[" section beginings, copied verbatim
# - lines containing an "=" sign which must fit in the following categorie.
# - "^\s*filename\s*=\s*path\s*$" where "path" is relative to this file
# But avoid directories, they are not portable.
# Copied verbatim.
# - "^\s*hashtype\s*=.*" where "hashtype" is one of the values supported
# by the re-generation script.
# Re-generated.
# - other lines are copied verbatim
# Substitution (${...:...}), extension ([buildout] extends = ...) and
# section inheritance (< = ...) are NOT supported (but you should really
# not need these here).
[instance-caucased]
filename = instance-caucased.cfg.jinja2
md5sum = 31dc85cce6e419235a92c3c7682a89d1
[instance]
filename = instance.cfg.jinja2
md5sum = d40bed5ccc457ff7dc99b618bf29b189
......@@ -4,78 +4,34 @@
"extends": "./schema-definitions.json#",
"title": "Input Parameters",
"properties": {
"server-port": {
"allOf": [
{
"$ref": "#/definitions/tcpv4port"
},
{
"title": "http port to use",
"description": "Caucase http port to use.",
"default": 8009
}
]
},
"server-https-port": {
"allOf": [
{
"$ref": "#/definitions/tcpv4port"
},
{
"title": "https port to use",
"description": "Caucase port to use for https connexion.",
"default": 8010
}
]
"base-port": {
"title": "Base TCP port",
"description": "If 80, caucase will also listen on 443. Otherwise, caucase will listen on port and port + 1.",
"type": "integer",
"default": 8009
},
"external-url": {
"title": "External http url",
"description": "External http url which point to caucase on http. This url will be added in signed certificate as CRL distribution point URI",
"title": "External URL of base port",
"description": "When provided, this URL will be added to issued certificate as the CRL distribution point.",
"type": "string",
"format": "uri"
},
"ca-subject": {
"title": "Subject of CA Certificate",
"description": "CA certificate subject as string. The format is: /C=XX/ST=State/L=City/OU=OUnit/O=Company/CN=CA Auth/emailAddress=xx@example.com. Only /CN is mandatory.",
"type": "string",
"default": "/C=FR/O=Company/CN=SlapOS Certificate Authority/emailAddress=xx@example.com"
},
"max-request-amount": {
"title": "Number of pending csr to accept",
"description": "Number of pending csr to accept. If this limit is reached, no more csr will be accepted by the CA.",
"service-auto-approve-amount": {
"title": "Number of service certificate requests to automatically approve",
"description": "Once that number has been reached, a user must validate further requests. Renewals do not count toward this number. Cannot be changed once set.",
"type": "integer",
"default": 10
"default": 0
},
"crt-life-time": {
"title": "Signed Certificate life time",
"description": "The time in seconds before a generated certificate will expire. Default: 365*24*60*60 seconds (1 year)",
"user-auto-approve-amount": {
"title": "Number of user certificate requests to automatically approve",
"description": "Once that number has been reached, a user must validate further requests. Renewals do not count toward this number. Cannot be changed once set.",
"type": "integer",
"default": 31536000,
"minimum": 86400
},
"crl-life-period": {
"title": "CRL life time period",
"description": "Number of individual certificate validity periods during which the CRL is valid. Default: 1/50.0",
"type": "number",
"default": 0.2
},
"ca-life-period": {
"title": "CA Certificate life period",
"description": "Number of individual certificate validity periods during which the CA certificate is valid. Default: 10",
"type": "number",
"default": 10
},
"crt-keep-time": {
"title": "Time before cleanup certificate content on CA",
"description": "The time in seconds before a generated certificate will be deleted on CA server. Set 0 to never delete. Default: 30*24*60*60 seconds (30 days)",
"default": 5184000,
"type": "integer"
"default": 1
},
"auto-sign-csr-amount": {
"title": "Number of CSR to sign automatically",
"description": "The number of CSR to sign automatically at startup. Has no effect if there is more than the specified value of csr submitted to caucase. This value should be as lowest as possible",
"default": 1,
"minimum": 1,
"key-length" : {
"title": "Key length",
"description": "Size, in bits, of the SSL key generated to authenticate users.",
"default": 2048,
"type": "integer"
}
}
......
......@@ -2,12 +2,8 @@
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Values returned by Caucase instantiation",
"properties": {
"http-url": {
"description": "Caucase URL on HTTP",
"type": "string"
},
"https-url": {
"description": "Caucase URL on HTTPS",
"url": {
"description": "Caucase URL",
"type": "string"
}
},
......
{% import "caucase" as caucase with context %}
{% set ipv6 = (ipv6_set | list)[0] -%}
{% set netloc = '[' ~ ipv6 ~ ']:' ~ slapparameter_dict.get('base-port', 8009) -%}
[directory]
recipe = slapos.cookbook:mkdirectory
etc = ${buildout:directory}/etc
promise = ${:etc}/promise
service-on-watch = ${:etc}/service
srv = ${buildout:directory}/srv
{{ caucase.caucased(
prefix='caucased',
buildout_bin_directory=bin_directory,
caucased_path='${directory:service-on-watch}/caucased',
data_dir='${directory:srv}/caucased',
netloc=netloc,
service_auto_approve_count=slapparameter_dict.get('service-auto-approve-amount', 0),
user_auto_approve_count=slapparameter_dict.get('user-auto-approve-amount', 1),
key_len=slapparameter_dict.get('key-length', 2048),
promise='${directory:promise}/caucased',
) }}
[publish]
recipe = slapos.cookbook:publish.serialised
url = {{ dumps('http://' ~ netloc) }}
[buildout]
parts =
publish
caucased
caucased-promise
[buildout]
parts = switch-softwaretype
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration.serialised
computer = ${slap-connection:computer-id}
partition = ${slap-connection:partition-id}
url = ${slap-connection:server-url}
key = ${slap-connection:key-file}
cert = ${slap-connection:cert-file}
[context]
bin-directory = {{ dumps(bin_directory) }}
caucase-jinja2-library = {{ dumps(caucase_jinja2_library) }}
instance-caucased = {{ dumps(instance_caucased) }}
[caucased]
recipe = slapos.recipe.template:jinja2
template = ${context:instance-caucased}
rendered = ${buildout:parts-directory}/instance-caucased.cfg
context =
key ipv6_set slap-configuration:ipv6
key slapparameter_dict slap-configuration:configuration
key bin_directory context:bin-directory
import-list =
file caucase context:caucase-jinja2-library
[switch-softwaretype]
recipe = slapos.cookbook:switch-softwaretype
default = caucased:rendered
# XXX: When will this name finally go away ?
RootSoftwareInstance = ${:default}
[buildout]
extends =
buildout.hash.cfg
../../stack/caucase/buildout.cfg
../../stack/slapos.cfg
parts =
slapos-cookbook
caucase-extra-eggs
instance-caucase
parts +=
instance
caucase-eggs
[instance-caucased]
recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/${:filename}
# XXX: following mode should be the default
mode = 644
[instance]
recipe = slapos.recipe.template:jinja2
# XXX: "template.cfg" is hardcoded in instanciation recipe
rendered = ${buildout:directory}/template.cfg
template = ${:_profile_base_location_}/${:filename}
context =
key bin_directory buildout:bin-directory
key develop_eggs_directory buildout:develop-eggs-directory
key eggs_directory buildout:eggs-directory
key caucase_jinja2_library caucase-jinja2-library:target
key instance_caucased instance-caucased:target
[versions]
slapos.recipe.template = 3.0
......@@ -90,6 +90,7 @@ This software release assigns the following port ranges by default:
balancer 2150-2199
zope 2200-*
jupyter 8888
caucase 8890,8891
==================== ==========
Non-zope partitions are unique in an ERP5 cluster, so you shouldn't have to
......
......@@ -350,12 +350,6 @@
"default": "",
"type": "string",
"format": "uri"
},
"crl-update-periodicity": {
"title": "Periodicity of CRL update",
"description": "Periodicity of CRL update, in cron format. The CRL will be downloaded from caucase URL and the new content will be saved if there was a change. Everytime a new CRL is writen, Apache reload will be called.",
"type": "string",
"default": "0 0 * * *"
}
},
"additionalProperties": {
......@@ -383,6 +377,34 @@
}
},
"type": "object"
},
"balancer": {
"description": "HTTP(S) load balancer proxy parameters",
"properties": {
"ssl": {
"description": "HTTPS certificate generation parameters",
"properties": {
"caucase-url":{
"title": "Caucase URL",
"description": "URL of caucase service to use. If not set, global setting will be used.",
"type": "string"
},
"csr": {
"title": "csr",
"description": "PEM-encoded certificate signature request to request server certificate with. If not provided, HTTPS will be disabled.",
"type": "string"
},
"max-crl-update-delay": {
"title": "Periodicity of CRL update (days)",
"description": "CRL will be updated from caucase at least this often.",
"type": "number",
"default": 1.0
}
},
"type": "object"
}
},
"type": "object"
}
}
}
caucase - CA for Users, CA for SErvices
Slapos integration
==================
This software release library provides macros to help you integrate caucase
into your software release.
To use this macros:
* extend ``stack/caucase/buildout.cfg`` in your Software Release to use it
* provide ``caucase-jinja2-library:target`` to the jinja templates where the macros are needed: ``key caucase caucase-jinja2-library:target``
* add ``{% import "caucase" as caucase with context %}`` in these jinja templates (note: context needed for ``dumps``, no changes are made to it)
Software
--------
This exposes the following sections:
- ``caucase-eggs``: Generate scripts to work with certificates using `caucase commands`_. In the software buildout's ``bin`` directory.
- ``caucase-jinja2-library``: Provide macros to generate sections that will use scripts created by ``caucase-eggs`` section.
.. _`caucase commands`: https://lab.nexedi.com/nexedi/caucase/blob/master/README.rst#commands
.. note::
``caucase-eggs`` needs to be listed in ``parts=`` of the software buildout or referenced by another installed part.
.. note:: ``caucase-jinja2-library`` needs to be referenced in an installed section using ``slapos.recipe.template`` from software buildout to make macros available in the the context of instance buildout. From ``software.cfg``:
.. code::
ini
[instance]
recipe = slapos.recipe.template:jinja2
import-list =
file caucase caucase-jinja2-library:target
Server
------
.. topic:: caucased(prefix, caucased_path, data_dir, netloc, service_auto_approve_count=0, key_len=None, promise=None)
This macro produces the following sections which you will want to reference sothey get instanciated:
- `<prefix>`: Creates `<caucased>` executable file to start `caucased`,
and `<data_dir>` directory for its data storage needs.
`caucased` will listend on `netloc`, which must be of the format
`hostname[:port]`, where hostname may be an IPv4 (ex: `127.0.0.1`), an IPv6
(ex: `[::1]`), or a domain name (ex: `localhost`). Port, when provided, must
be numeric. If port is not provided, it default to `80`.
If port is `80`, ``caucased`` will listen on `80` and `443` for given
hostname. This is *not* the recommended usage.
If port is not `80`, ``caucased`` will listen on it *and* its immediate next
higher port (ex: ``[::1]:8009`` will listen on both ``[::1]:8009`` and
``[::1]:8010``). This is the recommended usage.
- ``<prefix>-promise``: (only produced if ``<promise>`` is not None). Creates an
executable at the path given in ``<promise>``, which will attempt to connect to
``caucase`` server, and fail if it detects any anomaly (port not listening,
protocol error, certificate discrepancy...).
Client
------
.. topic:: ``rerequest(prefix, buildout_bin_directory, template, csr, key)``
- ``<prefix>``: Creates ``<rerequest>`` executable file to run ``caucase-rerequest``.
This script allows you to re-issue a CSR using a locally-generated private key.
.. topic:: ``updater(prefix, buildout_bin_directory, updater_path, url, data_dir, crt_path, ca_path, crl_path, key_path=None, on_renew=None, max_sleep=None, mode='service', template_csr_pem=None, openssl=None)``
- ``<prefix>``: Creates ``<updater>`` executable file to start ``caucase-updater``, and ``<data_dir>`` directory for its data storage needs.
``caucase-updater`` will monitor a key pair, corresponding CA certificate and CRL, and renew them before expiration.
.. note::
You can find more information about any argument mentioned above calling ``<command> --help <argument>``
[buildout]
extends =
buildout.hash.cfg
../../component/apache/buildout.cfg
../../component/nginx/buildout.cfg
../../component/curl/buildout.cfg
../../component/dash/buildout.cfg
../../component/openssl/buildout.cfg
../../component/bcrypt/buildout.cfg
../../stack/logrotate/buildout.cfg
../slapos.cfg
../../component/python-cryptography/buildout.cfg
parts =
instance-caucase
slapos-cookbook
[caucase-extra-eggs]
[caucase-eggs]
recipe = zc.recipe.egg
interpreter = python_ca
eggs =
gunicorn # for WSGI HTTP Server
futures
caucase # certificate authority
${bcrypt:egg}
# are also required
plone.recipe.command
collective.recipe.template
slapos.toolbox
${python-cryptography:egg}
caucase
scripts =
slapos-kill
gunicorn
caucase
caucase-cli
caucase-cliweb
[template-ca-download-base]
recipe = hexagonit.recipe.download
ignore-existing = true
download-only = true
url = ${:_profile_base_location_}/${:filename}
mode = 0644
caucase-probe
caucase-updater
caucased
caucased-manage
[template-httpd-auth-conf]
<= template-ca-download-base
[template-nginx-ca-conf]
<= template-ca-download-base
[caucase-jinja2-library-eggs]
recipe = zc.recipe.egg
eggs =
${slapos-cookbook:eggs}
plone.recipe.command
slapos.recipe.template
[template-caucase]
<= template-ca-download-base
[caucase-jinja2-library]
recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/${:filename}
[template-authenticated-server]
recipe = slapos.recipe.template:jinja2
template = ${:_profile_base_location_}/${:filename}
rendered = ${buildout:directory}/template-authenticated-server.cfg
context =
key apache_location apache:location
key template_logrotate_base template-logrotate-base:rendered
raw certificate_request_bin ${buildout:directory}/bin/caucase-cliweb
raw curl_executable_location ${curl:location}/bin/curl
raw dash_executable_location ${dash:location}/bin/dash
raw slapos_kill_bin ${buildout:directory}/bin/slapos-kill
raw template_httpd_auth_conf ${template-httpd-auth-conf:location}/${template-httpd-auth-conf:filename}
raw openssl_executable_location ${openssl:location}/bin/openssl
raw python_bin ${buildout:directory}/bin/${caucase-extra-eggs:interpreter}
[instance-caucase]
recipe = slapos.recipe.template:jinja2
template = ${:_profile_base_location_}/${:filename}
rendered = ${buildout:directory}/template.cfg
context =
key develop_eggs_directory buildout:develop-eggs-directory
key eggs_directory buildout:eggs-directory
key nginx_location nginx:location
key template_logrotate_base template-logrotate-base:rendered
raw caucase_template ${template-caucase:location}/${template-caucase:filename}
raw curl_executable_location ${curl:location}/bin/curl
raw caucase_bin ${buildout:directory}/bin/caucase
raw certificate_request_bin ${buildout:directory}/bin/caucase-cliweb
raw template_nginx_ca_conf ${template-nginx-ca-conf:location}/${template-nginx-ca-conf:filename}
raw dash_executable_location ${dash:location}/bin/dash
raw slapos_kill_bin ${buildout:directory}/bin/slapos-kill
raw gunicorn_bin ${buildout:directory}/bin/gunicorn
raw openssl_executable_location ${openssl:location}/bin/openssl
raw python_bin ${buildout:directory}/bin/${caucase-extra-eggs:interpreter}
mode = 0644
depends = ${caucase-jinja2-library-eggs:eggs}
[versions]
Flask-User = 0.6.19
bcrypt = 3.1.3
caucase = 0.1.4
futures = 3.1.1
gunicorn = 19.7.1
slapos.recipe.template = 4.3
smmap2 = 2.0.3
PyJWT = 1.6.4
# Required by:
# caucase==0.1.4
Flask-AlchemyDumps = 0.0.10
# Required by:
# Flask-User==0.6.19
Flask-Login = 0.4.0
# Required by:
# Flask-User==0.6.19
Flask-Mail = 0.9.1
# Required by:
# Flask-AlchemyDumps==0.0.10
# Flask-User==0.6.19
Flask-SQLAlchemy = 2.3.2
# Required by:
# Flask-AlchemyDumps==0.0.10
Flask-Script = 2.0.6
# Required by:
# Flask-User==0.6.19
Flask-WTF = 0.14.2
# Required by:
# Flask-AlchemyDumps==0.0.10
SQLAlchemy = 1.1.15
# Required by:
# Flask-AlchemyDumps==0.0.10
Unipath = 1.1
# Required by:
# Flask-WTF==0.14.2
WTForms = 2.1
# Required by:
# Flask-Mail==0.9.1
blinker = 1.4
# Required by:
# caucase==0.1.4
caucase = 0.9.5
pem = 17.1.0
# Required by:
# caucase==0.1.4
pyasn1-modules = 0.0.9
# Required by:
# Flask-User==0.6.19
pycryptodome = 3.4.7
PyJWT = 1.7.1
......@@ -13,22 +13,6 @@
# section inheritance (< = ...) are NOT supported (but you should really
# not need these here).
[template-httpd-auth-conf]
filename = template-httpd-auth.conf.in
md5sum = ea445b0a9b143d12b5700a71ac06293c
[template-nginx-ca-conf]
filename = ca-nginx.conf.in
md5sum = d8bebf1629aacffd619541f363687b4a
[template-authenticated-server]
filename = instance-auth-server.cfg.jinja2.in
md5sum = c005cfef03a0c2e504fcfa075e59934a
[template-caucase]
filename = instance-caucase.cfg.jinja2.in
md5sum = 589a0ad37abc28cf6e34e406e7b83eec
[instance-caucase]
filename = instance.cfg.in
md5sum = eb9d2ab646717d123b0472da5194d77f
[caucase-jinja2-library]
filename = caucase.jinja2.library
md5sum = da082c12f547eee3a33e98c535dcbc14
worker_processes {{ parameter_dict['workers-processes'] }};
pid {{ parameter_dict['pid-file'] }};
error_log {{ parameter_dict['error-log'] }};
daemon off;
events {
worker_connections 1024;
accept_mutex off;
}
http {
# include mime.types;
default_type application/octet-stream;
access_log {{ parameter_dict['access-log'] }} combined;
client_max_body_size 10M;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
sendfile on;
upstream app_server {
# for UNIX domain socket setups
server unix:{{ parameter_dict['socket'] }} fail_timeout=0;
}
{% if parameter_dict['cert-file'] and parameter_dict['key-file'] -%}
server {
listen [{{ parameter_dict['ip'] }}]:{{ parameter_dict['https-port'] }} ssl;
server_name _;
ssl_certificate {{ parameter_dict['cert-file'] }};
ssl_certificate_key {{ parameter_dict['key-file'] }};
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
keepalive_timeout 90s;
client_body_temp_path {{ parameter_dict['client-body-temp-path'] }};
proxy_temp_path {{ parameter_dict['proxy-temp-path'] }};
fastcgi_temp_path {{ parameter_dict['fastcgi-temp-path'] }};
uwsgi_temp_path {{ parameter_dict['uwsgi-temp-path'] }};
scgi_temp_path {{ parameter_dict['scgi-temp-path'] }};
location / {
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Host $http_host;
proxy_set_header Authorization $http_authorization;
proxy_pass_header Authorization;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
send_timeout 90;
proxy_pass http://app_server;
}
}
{% endif -%}
server {
listen [{{ parameter_dict['ip'] }}]:{{ parameter_dict['port'] }};
server_name _;
keepalive_timeout 90s;
client_body_temp_path {{ parameter_dict['client-body-temp-path'] }};
proxy_temp_path {{ parameter_dict['proxy-temp-path'] }};
fastcgi_temp_path {{ parameter_dict['fastcgi-temp-path'] }};
uwsgi_temp_path {{ parameter_dict['uwsgi-temp-path'] }};
scgi_temp_path {{ parameter_dict['scgi-temp-path'] }};
location ~ ^(/admin|/user) {
# http is not used for /admin and /user
}
location / {
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Host $http_host;
proxy_set_header Authorization $http_authorization;
proxy_pass_header Authorization;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
send_timeout 90;
proxy_pass http://app_server;
}
}
}
{% macro caucased(
prefix,
buildout_bin_directory,
caucased_path,
data_dir,
netloc,
service_auto_approve_count=0,
user_auto_approve_count=1,
key_len=None,
backup_dir=None,
promise=None
) -%}
[{{ prefix }}-directory]
recipe = slapos.cookbook:mkdirectory
data-dir = {{ data_dir }}
mode = 0750
[{{ prefix }}]
recipe = slapos.cookbook:wrapper
wrapper-path = {{ caucased_path }}
command-line = '{{ buildout_bin_directory }}/caucased'
--db '${ {{- prefix }}-directory:data-dir}/caucase.sqlite'
--server-key '${ {{- prefix }}-directory:data-dir}/server.key.pem'
--netloc '{{ netloc }}'
{% if key_len %}--key-len '{{ key_len }}' {%- endif %}
{% if backup_dir %}--backup-directory {{ backup_dir }} {%- endif %}
--service-auto-approve-count '{{ service_auto_approve_count }}'
--user-auto-approve-count '{{ user_auto_approve_count }}'
--lock-auto-approve-count
{% if promise -%}
[{{ prefix }}-promise]
recipe = slapos.cookbook:wrapper
wrapper-path = {{ promise }}
command-line = '{{ buildout_bin_directory }}/caucase-probe' 'http://{{ netloc }}'
{%- endif %}
{%- endmacro %}
{% macro updater(
prefix,
buildout_bin_directory,
updater_path,
url,
data_dir,
crt_path,
ca_path,
crl_path,
key_path=None,
on_renew=None,
max_sleep=None,
mode='service',
template_csr_pem=None,
openssl=None
) -%}
[{{ prefix }}-directory]
recipe = slapos.cookbook:mkdirectory
data-dir = {{ data_dir }}
{% if template_csr_pem -%}
[{{ prefix }}-provided-csr-content]
content = {{ dumps(template_csr_pem) }}
[{{ prefix }}-provided-csr]
recipe = slapos.recipe.template:jinja2
mode = 644
template = inline:{{ '{{ content }}' }}
rendered = ${ {{- prefix }}-directory:data-dir}/provided.csr.pem
context = key content {{ prefix }}-provided-csr-content:content
{{ rerequest(
prefix=prefix ~ '-csr',
buildout_bin_directory='{{ buildout_bin_directory }}',
template='{{ "\'$" + prefix }}-provided-csr:rendered}',
csr='${:csr}',
key=key_path,
)}}
{%- else -%}
[{{ prefix }}-csr]
recipe = plone.recipe.command
command = '{{ openssl }}' req -newkey rsa:2048 -batch -new -nodes -subj /CN=example.com -keyout '{{ key_path or crt_path }}' -out '${:csr}'
{%- endif %}
csr = ${ {{- prefix }}-directory:data-dir}/good.csr.pem
[{{ prefix }}]
recipe = slapos.cookbook:wrapper
wrapper-path = {{ updater_path }}
command-line = '{{ buildout_bin_directory }}/caucase-updater'
--ca-url '{{ url }}'
--cas-ca '${ {{- prefix }}-directory:data-dir}/cas.crt.pem'
--mode '{{ mode }}'
--csr '${ {{- prefix }}-csr:csr}'
--crt '{{ crt_path }}'
--ca '{{ ca_path }}'
--crl '{{ crl_path }}'
{% if key_path %}--key '{{ key_path }}' {%- endif %}
--on-renew '{{ on_renew }}'
{% if max_sleep %}--max-sleep '{{ max_sleep }}' {%- endif %}
{%- endmacro %}
{% macro rerequest(prefix, buildout_bin_directory, template, csr, key) -%}
[{{ prefix }}]
recipe = plone.recipe.command
command = '{{ buildout_bin_directory }}/caucase-rerequest' --template '{{ template }}' --csr '{{ csr }}' --key '{{ key }}'
{%- endmacro %}
[buildout]
extends =
{{ template_logrotate_base }}
parts =
authenticated-httpd-server
[authenticated-server-parameters]
ca-url =
common-name = instance@${slap-configuration:instance-title}
server-port = 8286
custom-httpd-file =
web-directory = ${directory:document-root}
[directory]
recipe = slapos.cookbook:mkdirectory
etc = ${buildout:directory}/etc
bin = ${buildout:directory}/bin
srv = ${buildout:directory}/srv
var = ${buildout:directory}/var
ssl = ${:etc}/ssl
run = ${:var}/run
log = ${:var}/log
scripts = ${:etc}/run
services = ${:etc}/service
promises = ${:etc}/promise
document-root = ${:srv}/private
[certificate-request-base]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:bin}/request-instance-certificate
cert-file = ${directory:ssl}/instance.cert.pem
key-file = ${directory:ssl}/instance.key.pem
ca-cert = ${directory:ssl}/cacert.pem
command-line = {{ certificate_request_bin }}
--crt-file ${:cert-file}
--key-file ${:key-file}
--ca-url ${authenticated-server-parameters:ca-url}
--ca-crt-file ${:ca-cert}
--no-check-certificate
# XXX - using --no-check-certificate which is insecure with https.
[server-certificate-request]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:scripts}/request-instance-certificate
command-line =
${certificate-request-base:wrapper-path}
--cn ${authenticated-server-parameters:common-name}
--request
[authenticated-httpd-conf-parameter]
ip = ${slap-configuration:ipv6-random}
port = ${authenticated-server-parameters:server-port}
pid-file = ${directory:run}/httpd-auth.pid
dav-lock = ${directory:var}/DavLockdb
access-log = ${directory:log}/httpd-auth-access.log
error-log = ${directory:log}/httpd-auth-error.log
cert-file = ${certificate-request-base:cert-file}
key-file = ${certificate-request-base:key-file}
ca-cert = ${certificate-request-base:ca-cert}
url = https://[${:ip}]:${:port}
private = ${authenticated-server-parameters:web-directory}
httpd-include-file = ${authenticated-server-parameters:custom-httpd-file}
crl =
[authenticated-httpd-conf]
recipe = slapos.recipe.template:jinja2
template = {{ template_httpd_auth_conf }}
rendered = ${directory:etc}/httpd-auth.conf
mode = 0744
context =
section parameter_dict authenticated-httpd-conf-parameter
[authenticated-httpd-graceful]
recipe = collective.recipe.template
input = inline:
#!{{ dash_executable_location }}
kill -USR1 $(cat ${authenticated-httpd-conf-parameter:pid-file})
output = ${directory:scripts}/authenticated-httpd-graceful
mode = 700
[authenticated-httpd-server]
recipe = slapos.cookbook:wrapper
command-line = {{ apache_location }}/bin/httpd -f ${authenticated-httpd-conf:rendered} -DFOREGROUND
wrapper-path = ${directory:services}/authenticated-httpd-server
wait-for-files =
${certificate-request-base:cert-file}
${certificate-request-base:key-file}
${certificate-request-base:ca-cert}
url = ${authenticated-httpd-conf-parameter:url}
depends =
${authenticated-httpd-promise:filename}
${authenticated-httpd-graceful:output}
${server-certificate-request:wrapper-path}
${logrotate-authenticated-httpd:name}
${certificate-renew-cron-entry:name}
[certificate-renew]
recipe = collective.recipe.template
input = inline:
#!{{ dash_executable_location }}
d=$({{ openssl_executable_location }} x509 -enddate -noout -in ${certificate-request-base:cert-file} | cut -d'=' -f 2)
cert_time=$(date -d "$d" +"%s")
now=$(date +"%s")
thresold=2592000 # 30*24*60*60 equivalent to one month in seconds
remind=$(($cert_time - $now))
if [ $remind -lt $thresold ]; then
exec ${certificate-request-base:wrapper-path} --renew
exec ${authenticated-httpd-graceful:output}
fi
output = ${directory:bin}/certificate-renew
mode = 700
[certificate-renew-cron-entry]
recipe = slapos.cookbook:cron.d
cron-entries = ${cron:cron-entries}
name = certificate-auto-renew
frequency = 5 6 * * 6
command = ${certificate-renew:output}