Commit bb390b40 authored by Vincent Pelletier's avatar 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.
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.",
"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
}
]
},
"server-https-port": {
"allOf": [
{
"$ref": "#/definitions/tcpv4port"
},
{
"title": "https port to use",
"description": "Caucase port to use for https connexion.",
"default": 8010
}
]
},
"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}
[logrotate-authenticated-httpd]
< = logrotate-entry-base
name = authenticated-httpd-server
log = ${authenticated-httpd-conf-parameter:access-log} ${authenticated-httpd-conf-parameter:access-log}
post = {{ slapos_kill_bin }} --pidfile ${authenticated-httpd-conf-parameter:pid-file} -s USR1
[authenticated-httpd-promise]
recipe = slapos.cookbook:check_url_available
path = ${directory:promises}/${:filename}
filename = authenticated-httpd-is-available
url = ${authenticated-httpd-conf-parameter:url}
check-secure = 1
dash_path = {{ dash_executable_location }}
curl_path = {{ curl_executable_location }}
cert-file = ${certificate-request-base:cert-file}
key-file = ${certificate-request-base:key-file}
ca-cert-file = ${certificate-request-base:ca-cert}
[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}
{% set part_list = [] -%}
{% set ipv6 = (ipv6 | list)[0] -%}
{% set default_subject = '/C=FR/O=Company/CN=SlapOS Certificate Authority/emailAddress=xx@example.com' -%}
{% if slapparameter_dict is not defined -%}
{% set slapparameter_dict = {} -%}
{% endif -%}
[ca-parameters]
server-port = {{ slapparameter_dict.get('server-port', 8009) }}
server-https-port = {{ slapparameter_dict.get('server-https-port', 8010) }}
ipv6 = {{ ipv6 }}
# Overrite this to set frontend or DNS URL (URL is used as CRL distribution point)
# Please set http not HTTPS scheme
crl-external-url = {{ slapparameter_dict.get('external-url', 'http://[${:ipv6}]:${:server-port}') }}
# /CN=XXX is required and should be unique
ca-subject = {{ slapparameter_dict.get('ca-subject', default_subject) }}
# Number of pending csr to accept
max-request-amount = {{ slapparameter_dict.get('max-request-amount', 10) }}
# one year (in seconds)
crt-life-time = {{ slapparameter_dict.get('crt-life-time', 31536000) }}
# crl-life-period correspond to about one week
crl-life-period = {{ slapparameter_dict.get('crl-life-period', 0.02) }}
# ca-life-period = ca-life-period * crt-life-time
ca-life-period = {{ slapparameter_dict.get('ca-life-period', 10) }}
# time before clean certificate on CA: 60*24*60*60
crt-keep-time = {{ slapparameter_dict.get('crt-keep-time', 5184000) }}
# number of csr to sign automaticaly, minimum value is 1
{% if int(slapparameter_dict.get('auto-sign-csr-amount', 1)) < 1 -%}
auto-sign-csr-amount = 1
{% else -%}
auto-sign-csr-amount = {{ slapparameter_dict.get('auto-sign-csr-amount', 1) }}
{% endif -%}
[directory]
recipe = slapos.cookbook:mkdirectory
etc = ${buildout:directory}/etc
bin = ${buildout:directory}/bin
srv = ${buildout:directory}/srv
var = ${buildout:directory}/var
run = ${:var}/run
log = ${:var}/log
scripts = ${:etc}/run
services = ${:etc}/service
promises = ${:etc}/promise
ssl=${:etc}/ssl
ca-dir = ${directory:srv}/ca
ca-temp = ${:ca-dir}/tmp
client-body-temp-path = ${:ca-temp}/client_body_temp_path
proxy-temp-path = ${:ca-temp}/proxy_temp_path
fastcgi-temp-path = ${:ca-temp}/fastcgi_temp_path
uwsgi-temp-path = ${:ca-temp}/uwsgi_temp_path
scgi-temp-path = ${:ca-temp}/scgi_temp_path
[nginx-certificate-request-base]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:bin}/request-base-certificate
cert-file = ${ca-nginx-ssl-config:cert}
key-file = ${ca-nginx-ssl-config:key}
ca-cert = ${directory:ssl}/cacert.pem
command-line = {{ certificate_request_bin }}
--crt-file ${:cert-file}
--key-file ${:key-file}
--ca-url http://[${ca-parameters:ipv6}]:${ca-parameters:server-port}
--ca-crt-file ${:ca-cert}
[nginx-certificate-request]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:scripts}/request-server-certificate
command-line =
${nginx-certificate-request-base:wrapper-path}
--cn nginx@certificate.authority
--request
[ca-nginx-ssl-config]
# if ssl certificate is signed write to file so that zero-knowledge can read
recipe = plone.recipe.command
command =
if [ -s "${:key}" ] && [ -s "${:cert}" ]; then
cat << EOF > ${:output}
[ca-nginx-ssl]
key=${:key}
cert=${:cert}
EOF
fi
key = ${directory:ssl}/ca-cert.key
cert = ${directory:ssl}/ca-cert.crt
update-command = ${:command}
output = ${directory:etc}/ca-nginx-ssl.cfg
stop-on-error = true
[ca-nginx-ssl]
recipe = slapos.cookbook:zero-knowledge.read
file-path = ${ca-nginx-ssl-config:output}
# initials values are empty, the section https (ssl) in nginx config will be skipped
cert =
key =
[ca-nginx-conf-parameter]
ip = ${ca-parameters:ipv6}
port = ${ca-parameters:server-port}
https-port = ${ca-parameters:server-https-port}
pid-file = ${directory:run}/nginx-ca.pid
access-log = ${directory:log}/nginx-ca-access.log
error-log = ${directory:log}/nginx-ca-error.log
cert-file = ${ca-nginx-ssl:cert}
key-file = ${ca-nginx-ssl:key}
ca-conf = ${caucase-conf:output}
workers-processes = 1
client-body-temp-path = ${directory:client-body-temp-path}
proxy-temp-path = ${directory:proxy-temp-path}
fastcgi-temp-path = ${directory:fastcgi-temp-path}
uwsgi-temp-path = ${directory:uwsgi-temp-path}
scgi-temp-path = ${directory:scgi-temp-path}
socket = ${caucase-gunicorn:socket}
[ca-nginx-conf]
recipe = slapos.recipe.template:jinja2
template = {{ template_nginx_ca_conf }}
rendered = ${directory:etc}/nginx-ca.conf
mode = 0700
context =
section parameter_dict ca-nginx-conf-parameter
[caucase-conf]
recipe = collective.recipe.template
# Values here are intended to be changed in your instance. override this section
input = inline:
ca-dir ${directory:ca-dir}
# enable debug
# debug
# log-file ${directory:log}/ca-server.log
subject ${ca-parameters:ca-subject}
max-request-amount ${ca-parameters:max-request-amount}
external-url ${ca-parameters:crl-external-url}
# one year (in seconds)
crt-life-time ${ca-parameters:crt-life-time}
# crl-life-period correspond to about one week
crl-life-period ${ca-parameters:crl-life-period}
# ca-life-time = ca-life-period * crt-life-time
ca-life-period ${ca-parameters:ca-life-period}
# time before clean certificate on CA: 60*24*60*60
crt-keep-time ${ca-parameters:crt-keep-time}
# number of csr to sign automaticaly
auto-sign-csr-amount ${ca-parameters:auto-sign-csr-amount}
output = ${directory:etc}/ca.conf
mode = 700
[ca-nginx-graceful]
recipe = collective.recipe.template
input = inline:#!{{ dash_executable_location }}
kill -HUP "$(cat '${ca-nginx-conf-parameter:pid-file}')"
output = ${directory:scripts}/ca-server-graceful
mode = 700
[caucase-gunicorn]
recipe = slapos.cookbook:wrapper
socket = ${directory:ca-dir}/ng.sock
command-line = {{ gunicorn_bin }} caucase.wsgi:app -b unix:${:socket} -e CA_CONFIGURATION_FILE=${caucase-conf:output} --error-logfile ${:log-file} --pid ${:pid-file} --capture-output --timeout 60 --threads 2 --log-level error --preload
log-file = ${directory:log}/ca-gunicorn-error.log
pid-file = ${directory:run}/ca-gunicorn.pid
wrapper-path = ${directory:services}/ca-gunicorn
[caucase-server]
recipe = slapos.cookbook:wrapper
command-line = {{ nginx_location }}/sbin/nginx -p ${directory:ca-dir} -c ${ca-nginx-conf:rendered}
wrapper-path = ${directory:services}/caucase-server
url = https://[${ca-parameters:ipv6}]:${ca-parameters:server-https-port}
http-url = ${ca-parameters:crl-external-url}
depends =
${nginx-certificate-request:wrapper-path}
${caucase-https-server-promise:filename}
${ca-nginx-graceful:output}
${ca-certificate-renew-cron-entry:name}
${logrotate-ca-nginx:name}
# Disabled to be re-implemented.
# ${caucase-server-promise:filename}
[ca-certificate-renew-cron-entry]
recipe = slapos.cookbook:cron.d
cron-entries = ${cron:cron-entries}
name = ca-server-certificate-auto-renew
# check renew every-week
time = weekly
# 2592000 = 30*24*60*60 equivalent to one month in seconds
command = ${nginx-certificate-request-base:wrapper-path} --renew --threshold 2592000 --on-renew="${ca-nginx-graceful:output}"
[logrotate-ca-nginx]
< = logrotate-entry-base
name = caucase-nginx-server
log = ${ca-nginx-conf-parameter:access-log} ${ca-nginx-conf-parameter:access-log}
post = {{ slapos_kill_bin }} --pidfile ${ca-nginx-conf-parameter:pid-file} -s USR1
# This promise is disabled as it requires user to take action so the buildout
# will fail for way too long, and overload master. Please reimplement on a
# better way
#[caucase-server-promise]
#recipe = slapos.cookbook:check_url_available
#path = ${directory:promises}/${:filename}
#filename = caucase-server-listening-on-tcp
#url = http://[${ca-parameters:ipv6}]:${ca-parameters:server-port}
#dash_path = {{ dash_executable_location }}
#curl_path = {{ curl_executable_location }}
#
[caucase-https-server-promise]
recipe = slapos.cookbook:check_url_available
path = ${directory:promises}/${:filename}
filename = caucase-server-https-on-${ca-parameters:server-https-port}
url = https://[${ca-parameters:ipv6}]:${ca-parameters:server-https-port}
check-secure = 1
dash_path = {{ dash_executable_location }}
curl_path = {{ curl_executable_location }}
{% if publish_parameter is defined and publish_parameter == 'yes' -%}
[publish-connection-parameter]
recipe = slapos.cookbook:publish.serialised
http-url = ${caucase-server:http-url}
https-url = ${caucase-server:url}
init-user = admin
{% do part_list.append('publish-connection-parameter') -%}
{% endif -%}
# Used for ERP5 resiliency or (more probably)
# webrunner resiliency with erp5 inside.
[resiliency-exclude-file]
# Generate rdiff exclude file
recipe = slapos.recipe.template:jinja2
mode = 644
template = inline:
${directory:log}/**
rendered = ${directory:srv}/exporter.exclude
{% do part_list.append('resiliency-exclude-file') -%}
[buildout]
extends =
{{ template_logrotate_base }}
parts =
caucase-server
# Complete parts with sections
{{ part_list | join('\n ') }}
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
[buildout]
parts =
switch-softwaretype
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
[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}
[dynamic-template-caucase]
recipe = slapos.recipe.template:jinja2
filename = ${:_buildout_section_name_}.cfg
rendered = ${buildout:parts-directory}/${:_buildout_section_name_}/${:filename}
template = {{ caucase_template }}
extensions = jinja2.ext.do
extra-context =
context =
key ipv4 slap-configuration:ipv4
key ipv6 slap-configuration:ipv6
key develop_eggs_directory buildout:develop-eggs-directory
key eggs_directory buildout:eggs-directory
key slapparameter_dict slap-configuration:configuration
raw gunicorn_bin {{ gunicorn_bin }}
raw template_logrotate_base {{ template_logrotate_base }}
raw certificate_request_bin {{ certificate_request_bin }}
raw template_nginx_ca_conf {{ template_nginx_ca_conf }}
raw nginx_location {{ nginx_location }}
raw slapos_kill_bin {{ slapos_kill_bin }}
raw dash_executable_location {{ dash_executable_location }}
raw curl_executable_location {{ curl_executable_location }}
raw publish_parameter yes
[switch-softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${dynamic-template-caucase:rendered}
Listen [{{ parameter_dict['ip'] }}]:{{ parameter_dict['port'] }}
LoadModule unixd_module modules/mod_unixd.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule mime_module modules/mod_mime.so
LoadModule dir_module modules/mod_dir.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule alias_module modules/mod_alias.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so
LoadModule env_module modules/mod_env.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
ServerAdmin admin@
TypesConfig conf/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
ServerTokens Prod
ServerSignature Off
TraceEnable Off
PidFile "{{ parameter_dict['pid-file'] }}"
ErrorLog "{{ parameter_dict['error-log'] }}"
# Default apache log format with request time in microsecond at the end
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined
CustomLog "{{ parameter_dict['access-log'] }}" combined
# SSL Configuration
Define SSLConfigured
SSLCertificateFile {{ parameter_dict['cert-file'] }}
SSLCertificateKeyFile {{ parameter_dict['key-file'] }}
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLRandomSeed startup /dev/urandom 256
SSLRandomSeed connect builtin
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite 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
SSLHonorCipherOrder on
SSLEngine On
<Directory />
Options FollowSymLinks
AllowOverride None
Allow from all
</Directory>
<VirtualHost *:{{ parameter_dict['port'] }}>
DavLockDB {{ parameter_dict['dav-lock'] }}
SSLVerifyClient require
RequestHeader set REMOTE_USER %{SSL_CLIENT_S_DN_CN}s
SSLCACertificateFile {{ parameter_dict['ca-cert'] }}
{% if parameter_dict['crl'] -%}
SSLCARevocationCheck chain
SSLCARevocationFile {{ parameter_dict['crl'] }}
{%- endif %}
Alias / {{ parameter_dict['private'] }}/
<Directory {{ parameter_dict['private'] }}>
DirectoryIndex disabled
DAV On
Options Indexes FollowSymLinks
Order Allow,Deny
Allow from all
</Directory>
</VirtualHost>
{% if parameter_dict.get('httpd-include-file', '') -%}
# Custom apache configuration here
Include {{ parameter_dict['httpd-include-file'] }}
{% endif -%}
......@@ -62,7 +62,7 @@ extends =
../../component/postfix/buildout.cfg
../../component/zbarlight/buildout.cfg
../monitor/buildout.cfg
../../software/caucase/software.cfg
../../stack/caucase/buildout.cfg
../../software/jupyter/software.cfg
../../software/neoppod/software-common.cfg
# keep neoppod extends last
......@@ -149,9 +149,6 @@ extra-ldflags = -Wl,-rpath=${gcc:location}/lib -Wl,-rpath=${gcc:location}/lib64
[instance-jupyter-notebook]
rendered = ${buildout:directory}/template-jupyter.cfg
[instance-caucase]
rendered = ${buildout:directory}/instance-caucase.cfg
[download-base]
<= download-base-neo
url = ${:_profile_base_location_}/${:filename}
......@@ -233,7 +230,7 @@ context =
key bin_directory buildout:bin-directory
key buildout_bin_directory buildout:bin-directory
key cairo_location cairo:location
key caucase_template instance-caucase:rendered
key caucase_jinja2_library caucase-jinja2-library:target
key coreutils_location coreutils:location
key cups_location cups:location
key curl_location curl:location
......@@ -442,6 +439,7 @@ initialization =
[eggs]
<= neoppod
eggs = ${neoppod:eggs}
${caucase-eggs:eggs}
${numpy:egg}
${matplotlib:egg}
${lxml-python:egg}
......@@ -571,6 +569,7 @@ eggs = ${neoppod:eggs}
# installation of python, which we don't want on an instance
interpreter = ${buildout:python}
scripts =
${caucase-eggs:scripts}
apachedex
repozo
runzope
......
......@@ -66,7 +66,7 @@ md5sum = 0969fbb25b05c02ef3c2d437b2f4e1a0
[template]
filename = instance.cfg.in
md5sum = be1466bfce26211e1f0b9e5cee47fe44
md5sum = 278781b66fc7b208d9090005019abb7a
[monitor-template-dummy]
filename = dummy.cfg
......@@ -74,7 +74,7 @@ md5sum = d41d8cd98f00b204e9800998ecf8427e
[template-erp5]
filename = instance-erp5.cfg.in
md5sum = acd108217ff7a1b02b338c01c9c4aa27
md5sum = 6c463effae65d8269586dfa51bd3f1f1
[template-zeo]
filename = instance-zeo.cfg.in
......@@ -82,11 +82,11 @@ md5sum = d400c3d449ce437a0ded77ee3d5c5df2
[template-zope]
filename = instance-zope.cfg.in
md5sum = 1a06ffa9f54e59604d4fedac0f6a99e7
md5sum = 34b613d297a300d41c59c02ca12e6f84
[template-balancer]
filename = instance-balancer.cfg.in
md5sum = 016c56374566b8ea2a1cdb7c8ada3ea7
md5sum = 7fcedcacb0558e770cbb1c1d63322ea4
[template-haproxy-cfg]
filename = haproxy.cfg.in
......
{% import "caucase" as caucase with context %}
{% set part_list = [] -%}
{% set ssl_parameter_dict = slapparameter_dict.get('ssl', {}) %}
{% set caucase_url = slapparameter_dict.get('caucase-url', '') -%}
{% macro section(name) %}{% do part_list.append(name) %}{{ name }}{% endmacro -%}
{% set use_ipv6 = slapparameter_dict.get('use-ipv6', False) -%}
{% set ssl_parameter_dict = slapparameter_dict['ssl'] -%}
{#
XXX: This template only supports exactly one IPv4 and (if ipv6 is used) one IPv6
per partition. No more (undefined result), no less (IndexError).
......@@ -21,80 +20,23 @@ per partition. No more (undefined result), no less (IndexError).
recipe = slapos.recipe.template:jinja2
mode = 644
[simplefile]
< = jinja2-template-base
template = inline:{{ '{{ content }}' }}
{% macro simplefile(section_name, file_path, content, mode='') -%}
{% set content_section_name = section_name ~ '-content' -%}
[{{ content_section_name }}]
content = {{ dumps(content) }}
[{{ section(section_name) }}]
< = simplefile
rendered = {{ file_path }}
context = key content {{content_section_name}}:content
mode = {{ mode }}
{%- endmacro %}
[certificate-request-base]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:bin}/request-instance-certificate
command-line = {{ parameter_dict['bin-directory'] }}/caucase-cliweb
--crt-file ${apache-conf-ssl:cert}
--key-file ${apache-conf-ssl:key}
--crl-file ${apache-conf-ssl:crl}
--ca-url {{ caucase_url }}
--ca-crt-file ${apache-conf-ssl:ca-cert}
{{ caucase.updater(
prefix='caucase-updater',
buildout_bin_directory=parameter_dict['bin-directory'],
updater_path='${directory:services-on-watch}/caucase-updater',
url=ssl_parameter_dict['caucase-url'],
data_dir='${directory:srv}/caucase-updater',
crt_path='${apache-conf-ssl:cert}',
ca_path='${apache-conf-ssl:ca-cert}',
crl_path='${apache-conf-ssl:crl}',
key_path='${apache-conf-ssl:key}',
on_renew='${apache-graceful:output}',
max_sleep=ssl_parameter_dict.get('max-crl-update-delay', 1.0),
template_csr_pem=ssl_parameter_dict.get('csr'),
openssl=parameter_dict['openssl'] ~ '/bin/openssl',
)}}
{% do section('caucase-updater') -%}
{% macro request_cert(name, common_name) -%}
{% set get_crl_periodicity = slapparameter_dict.get('crl-update-periodicity', 'daily') -%}
[{{ section(name ~ '-certificate-request') }}]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:services}/request-{{ name }}-certificate
command-line =
${certificate-request-base:wrapper-path}
--cn {{ common_name }}
--request
[{{ section(name ~ '-renew-cron-entry') }}]
recipe = slapos.cookbook:cron.d
cron-entries = ${cron:cron-entries}
name = {{ name }}-certificate-auto-renew
time = weekly
# 2592000 = 30*24*60*60 equivalent to one month in seconds
command = ${certificate-request-base:wrapper-path} --renew --threshold 2592000 --on-renew="${apache-graceful:output}"
[{{ section(name ~ '-download-crl') }}]
# download the crl for the first time
recipe = plone.recipe.command
command =
if [ ! -s "${apache-conf-ssl:crl}" ]; then
${certificate-request-base:wrapper-path} --update-crl
fi
update-command = ${:command}
stop-on-error = true
[{{ section(name ~ '-update-crl-cron-entry') }}]
recipe = slapos.cookbook:cron.d
cron-entries = ${cron:cron-entries}
name = {{ name }}-update-crl
time = {{ get_crl_periodicity }}
# XXX - Update crl call apache graceful restart, it's not recommended to check crl too often, Apache
# has an issue with reload and can be frozen and stop responding. Default periodicity time = daily
command = ${certificate-request-base:wrapper-path} --update-crl --on-crl-update="${apache-graceful:output}"
{%- endmacro %}
{% if use_ipv6 -%}
[zope-tunnel-base]
recipe = slapos.cookbook:ipv4toipv6
runner-path = ${directory:services}/${:base-name}
6tunnel-path = {{ parameter_dict['6tunnel'] }}/bin/6tunnel
shell-path = {{ parameter_dict['dash'] }}/bin/dash
ipv4 = {{ ipv4 }}
{% endif -%}
{% set haproxy_dict = {} -%}
{% set apache_dict = {} -%}
{% set zope_virtualhost_monster_backend_dict = {} %}
......@@ -111,18 +53,7 @@ ipv4 = {{ ipv4 }}
{% if webdav -%}
{% do has_webdav.append(None) %}
{% endif -%}
{% if use_ipv6 -%}
{% set current_port = next_port() -%}
[{{ section('zope-tunnel-' ~ current_port) }}]
< = zope-tunnel-base
base-name = {{ 'zeo-tunnel-' ~ current_port }}
ipv4-port = {{ current_port }}
ipv6-port = {{ zope_address.split(']:')[1] }}
ipv6 = {{ zope_address.split(']:')[0][1:] }}
{% set zope_effective_address = ipv4 ~ ":" ~ current_port -%}
{% else -%}
{% set zope_effective_address = zope_address -%}
{% endif -%}
{% do zope_family_address_list.append((zope_effective_address, maxconn, webdav)) -%}
{# # Generate entries with rewrite rule for test runnners #}
......@@ -162,7 +93,7 @@ ipv6 = {{ zope_address.split(']:')[0][1:] }}
{% set internal_scheme = 'http' -%}
{% set external_scheme = 'https' -%}
{% endif -%}
{% do apache_dict.__setitem__(family_name, (next_port(), external_scheme, internal_scheme ~ '://' ~ ipv4 ~ ':' ~ haproxy_port ~ backend_path, ssl_authentication)) -%}
{% do apache_dict.__setitem__(family_name, (next_port(), external_scheme, internal_scheme ~ '://' ~ ipv4 ~ ':' ~ haproxy_port ~ backend_path, slapparameter_dict['ssl-authentication-dict'].get(family_name, False))) -%}
{% endfor -%}
[haproxy-cfg-parameter-dict]
......@@ -184,8 +115,6 @@ wrapper-path = ${directory:services}/haproxy
command-line = "{{ parameter_dict['haproxy'] }}/sbin/haproxy" -f "${haproxy-cfg:rendered}"
hash-files = ${haproxy-cfg:rendered}
{# TODO: build socat and wrap it as "${directory:bin}/haproxy-ctl" to connect to "${haproxy-cfg-parameter-dict:socket-path}" #}
[apache-conf-ssl]
cert = ${directory:apache-conf}/apache.crt
key = ${directory:apache-conf}/apache.pem
......@@ -203,13 +132,13 @@ access-log = ${directory:log}/apache-access.log
# Apache 2.4's default value (60 seconds) can be a bit too short
timeout = 300
# Basic SSL server configuration
cert = ${apache-ssl:cert}
key = ${apache-ssl:key}
cert = ${apache-conf-ssl:cert}
key = ${apache-conf-ssl:key}
cipher =
ssl-session-cache = ${directory:log}/apache-ssl-session-cache
# Client x509 auth
ca-cert = ${apache-ssl-client:cert}
crl = ${apache-ssl-client:crl}
ca-cert = ${apache-conf-ssl:ca-cert}
crl = ${apache-conf-ssl:crl}
[apache-conf]
< = jinja2-template-base
......@@ -227,13 +156,12 @@ wait-for-files =
[apache-graceful]
recipe = collective.recipe.template
output = ${directory:bin}/apache-httpd-graceful
mode = 700
input = inline:
#!/bin/sh
kill -USR1 "$(cat '${apache-conf-parameter-dict:pid-file}')"
output = ${directory:bin}/apache-httpd-graceful
mode = 700
[{{ section('apache-promise') }}]
# Check any apache port in ipv4, expect other ports and ipv6 to behave consistently
recipe = slapos.cookbook:check_port_listening
......@@ -253,39 +181,6 @@ recipe = slapos.cookbook:publish.serialised
monitor-base-url = ${monitor-publish-parameters:monitor-base-url}
[apache-ssl]
{% if ssl_parameter_dict.get('key') -%}
key = ${apache-ssl-key:rendered}
cert = ${apache-ssl-cert:rendered}
{{ simplefile('apache-ssl-key', '${apache-conf-ssl:key}', ssl_parameter_dict['key']) }}
{{ simplefile('apache-ssl-cert', '${apache-conf-ssl:cert}', ssl_parameter_dict['cert']) }}
{% elif caucase_url -%}
key = ${apache-conf-ssl:key}
cert = ${apache-conf-ssl:cert}
{{ request_cert('erp5', 'instance.apache@erp5') }}
{% else %}
recipe = plone.recipe.command
command = "{{ parameter_dict['openssl'] }}/bin/openssl" req -newkey rsa -batch -new -x509 -days 3650 -nodes -keyout "${:key}" -out "${:cert}"
key = ${apache-conf-ssl:key}
cert = ${apache-conf-ssl:cert}
{%- endif %}
[apache-ssl-client]
{% if ssl_parameter_dict.get('ca-cert') -%}
cert = ${apache-ssl-ca:rendered}
crl = ${apache-ssl-crl:rendered}
{{ simplefile('apache-ssl-ca', '${apache-conf-ssl:ca-cert}', ssl_parameter_dict['ca-cert']) }}
{{ simplefile('apache-ssl-crl', '${apache-conf-ssl:crl}', ssl_parameter_dict['crl']) }}
{% elif caucase_url -%}
cert = ${apache-conf-ssl:ca-cert}
crl = ${apache-conf-ssl:crl}
{% else %}
cert =
crl =
{%- endif %}
[{{ section('logrotate-apache') }}]
< = logrotate-entry-base
name = apache
......@@ -299,15 +194,11 @@ bin = ${buildout:directory}/bin
etc = ${buildout:directory}/etc
promise = ${:etc}/promise
services = ${:etc}/run
services-on-watch = ${:etc}/service
var = ${buildout:directory}/var
run = ${:var}/run
log = ${:var}/log
ca-dir = ${buildout:directory}/srv/ssl
requests = ${:ca-dir}/requests
private = ${:ca-dir}/private
certs = ${:ca-dir}/certs
newcerts = ${:ca-dir}/newcerts
crl = ${:ca-dir}/crl
srv = ${buildout:directory}/srv
apachedex = ${monitor-directory:private}/apachedex
[{{ section('resiliency-exclude-file') }}]
......
{% import "root_common" as root_common with context -%}
{% import "caucase" as caucase with context %}
{% set frontend_dict = slapparameter_dict.get('frontend', {}) -%}
{% set has_frontend = frontend_dict.get('software-url', '') != '' -%}
{% set site_id = slapparameter_dict.get('site-id', 'erp5') -%}
......@@ -19,13 +20,13 @@
{% set test_runner_enabled = mariadb_test_database_amount > 0 %}
{% endif -%}
{% set monitor_base_url_dict = {} -%}
{% set caucase_url = slapparameter_dict.get('caucase', {}).pop('url', '') -%}
{% set monitor_dict = slapparameter_dict.get('monitor', {}) %}
{% set crl_update_period = slapparameter_dict.get('caucase', {}).pop('crl-update-periodicity', 'daily') -%}
{% set use_ipv6 = slapparameter_dict.get('use-ipv6', False) -%}
[request-common]
<= request-common-base
config-use-ipv6 = {{ dumps(slapparameter_dict.get('use-ipv6', False)) }}
config-computer-memory-percent-threshold = {{ dumps(monitor_dict.get('computer-memory-percent-threshold', 80)) }}
{% set caucase_url = slapparameter_dict.get('caucase', {}).pop('url', '') -%}
{% macro request(name, software_type, config_key, config, ret={'url': True}, key_config={}) -%}
{% do config.update(slapparameter_dict.get(config_key, {})) -%}
......@@ -53,6 +54,44 @@ config-{{ k }} = {{ '${' ~ v ~ '}' }}
config-name = {{ name }}
{% endmacro -%}
[directory]
recipe = slapos.cookbook:mkdirectory
etc = ${buildout:directory}/etc
promise = ${:etc}/promise
service-on-watch = ${:etc}/service
srv = ${buildout:directory}/srv
backup-caucased = ${:srv}/backup/caucased
{% set caucase_dict = slapparameter_dict.get('caucase', {}) -%}
{% set caucase_url = caucase_dict.get('url') -%}
{% if not caucase_url -%}
{% if use_ipv6 -%}
{% set caucase_host = '[' ~ (ipv6_set | list)[0] ~ ']' %}
{%- else -%}
{% set caucase_host = (ipv4_set | list)[0] %}
{%- endif %}
{% set caucase_port = caucase_dict.get('base-port', 8890) -%}
{% set caucase_netloc = caucase_host ~ ':' ~ caucase_port -%}
{% set caucase_url = 'http://' ~ caucase_netloc -%}
{{ caucase.caucased(
prefix='caucased',
buildout_bin_directory=bin_directory,
caucased_path='${directory:service-on-watch}/caucased',
backup_dir='${directory:backup-caucased}',
data_dir='${directory:srv}/caucased',
netloc=caucase_netloc,
service_auto_approve_count=caucase_dict.get('service-auto-approve-amount', 1),
user_auto_approve_count=caucase_dict.get('user-auto-approve-amount', 0),
key_len=caucase_dict.get('key-length', 2048),
promise='${directory:promise}/caucased',
)}}
{% do root_common.section('caucased') -%}
{% do root_common.section('caucased-promise') -%}
{% endif -%}
{% do publish_dict.__setitem__('caucase-http-url', caucase_url) -%}
{% set balancer_dict = slapparameter_dict.get('balancer', {}) -%}
{% do balancer_dict.setdefault('ssl', {}).setdefault('caucase-url', caucase_url) -%}
{{ request('memcached-persistent', 'kumofs', 'kumofs', {'tcpv4-port': 2000}, {'url': True, 'monitor-base-url': False}, key_config={'monitor-passwd': 'monitor-htpasswd:passwd'}) }}
{{ request('memcached-volatile', 'kumofs', 'memcached', {'tcpv4-port': 2010, 'ram-storage-size': 64}, {'url': True, 'monitor-base-url': False}, key_config={'monitor-passwd': 'monitor-htpasswd:passwd'}) }}
{{ request('mariadb', 'mariadb', 'mariadb', {'tcpv4-port': 2099, 'max-slowqueries-threshold': monitor_dict.get('max-slowqueries-threshold', 1000), 'slowest-query-threshold': monitor_dict.get('slowest-query-threshold', ''), 'test-database-amount': test_runner_total_database_count}, {'database-list': True, 'test-database-list': True, 'monitor-base-url': False}, key_config={'monitor-passwd': 'monitor-htpasswd:passwd'}) }}
......@@ -64,14 +103,6 @@ config-name = {{ name }}
connection-url = smtp://127.0.0.2:0/
{%- endif %}
{% if caucase_url -%}
{% do publish_dict.__setitem__('caucase-http-url', caucase_url) -%}
[request-caucase]
connection-http-url = {{ caucase_url }}
{%- else %}
{{ request('caucase', 'caucase', 'caucase', {'server-port': 8890, 'server-https-port': 8891, 'auto-sign-csr-amount': 2}, {'http-url': True, 'https-url': False}) }}
{% endif -%}
{# ZODB -#}
{% set zodb_dict = {} -%}
{% set storage_dict = {} -%}
......@@ -124,8 +155,8 @@ return =
{% endif -%}
config-bt5 = {{ dumps(slapparameter_dict.get('bt5', bt5_default_list)) }}
config-bt5-repository-url = {{ dumps(slapparameter_dict.get('bt5-repository-url', local_bt5_repository)) }}
config-caucase-url = ${request-caucase:connection-http-url}
config-cloudooo-url = {{ dumps(slapparameter_dict.get('cloudooo-url', default_cloudooo_url)) }}
config-caucase-url = {{ dumps(caucase_url) }}
config-deadlock-debugger-password = ${publish-early:deadlock-debugger-password}
config-developer-list = {{ dumps(slapparameter_dict.get('developer-list', [inituser_login])) }}
config-saucelabs-dict = {{ dumps(slapparameter_dict.get('saucelabs-dict', {})) }}
......@@ -242,7 +273,6 @@ config-url = ${request-jupyter:connection-url}
{% endif -%}
{%- endif %}
{% set balancer_dict = slapparameter_dict.get('balancer', {}) -%}
[request-balancer]
<= request-common
name = balancer
......@@ -258,7 +288,6 @@ return =
{% endif %}
{% endfor -%}
{% do monitor_base_url_dict.__setitem__('request-balancer', '${' ~ 'request-balancer' ~ ':connection-monitor-base-url}') -%}
config-zope-family-dict = {{ dumps(zope_family_parameter_dict) }}
config-tcpv4-port = {{ dumps(balancer_dict.get('tcpv4-port', 2150)) }}
{% for zope_section_id, name in zope_address_list_id_dict.items() -%}
......@@ -269,11 +298,9 @@ config-{{ name }}-test-runner-address-list = {{ ' ${' ~ zope_section_id ~ ':conn
{% endfor -%}
# XXX: should those really be same for all families ?
config-haproxy-server-check-path = {{ dumps(balancer_dict.get('haproxy-server-check-path', '/') % {'site-id': site_id}) }}
config-ssl = {{ dumps(balancer_dict.get('ssl', {})) }}
config-monitor-passwd = ${monitor-htpasswd:passwd}
config-ssl = {{ dumps(balancer_dict['ssl']) }}
config-name = ${:name}
config-caucase-url = ${request-caucase:connection-http-url}
config-crl-update-periodicity = {{ crl_update_period }}
config-backend-path-dict = {{ dumps(zope_backend_path_dict) }}
config-ssl-authentication-dict = {{ dumps(ssl_authentication_dict) }}
config-apachedex-promise-threshold = {{ dumps(monitor_dict.get('apachedex-promise-threshold', 70)) }}
......@@ -401,4 +428,3 @@ password = ${monitor-htpasswd:passwd}
{% for key, value in monitor_base_url_dict.items() -%}
{{ key }} = {{ value }}
{% endfor %}
......@@ -55,23 +55,12 @@ environment +=
TZ={{ slapparameter_dict['timezone'] }}
MATPLOTLIBRC={{ parameter_dict['matplotlibrc'] }}
INSTANCE_HOME=${:instance-home}
CAUCASE={{ slapparameter_dict['caucase-url'] }}
{% if slapparameter_dict.get('wendelin-core-zblk-fmt') %}
WENDELIN_CORE_ZBLK_FMT={{ slapparameter_dict['wendelin-core-zblk-fmt'] }}
{% endif %}
${:environment-extra}
[test-certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${binary-link:target-directory}/openssl
ca-dir = ${directory:test-ca-dir}
requests-directory = ${directory:test-ca-requests}
wrapper = ${directory:services}/test-ca
ca-private = ${directory:test-ca-private}
ca-certs = ${directory:test-ca-certs}
ca-newcerts = ${directory:test-ca-newcerts}
ca-crl = ${directory:test-ca-crl}
[directory]
recipe = slapos.cookbook:mkdirectory
bin = ${buildout:directory}/bin
......@@ -92,22 +81,11 @@ run = ${:var}/run
services = ${:etc}/run
service-on-watch = ${:etc}/service
srv = ${buildout:directory}/srv
ca-dir = ${:srv}/ssl
tmp = ${buildout:directory}/tmp
var = ${buildout:directory}/var
promises = ${:etc}/promise
unit-test-path = ${:srv}/test-instance/unit_test
test-ca-dir = ${:srv}/test-ca
test-ca-requests = ${:test-ca-dir}/requests
test-ca-private = ${:test-ca-dir}/private
test-ca-certs = ${:test-ca-dir}/certs
test-ca-newcerts = ${:test-ca-dir}/newcerts
test-ca-crl = ${:test-ca-dir}/crl
ca-dir = ${:srv}/ca
ca-requests = ${:ca-dir}/requests
ca-private = ${:ca-dir}/private
ca-certs = ${:ca-dir}/certs
ca-newcerts = ${:ca-dir}/newcerts
ca-crl = ${:ca-dir}/crl
# Used for ERP5 resiliency or (more probably)
# webrunner resiliency with erp5 inside.
......@@ -130,20 +108,6 @@ recipe = slapos.cookbook:symbolic.link
target-directory = ${directory:bin}
link-binary = {{ dumps(parameter_dict['link-binary']) }}
[certificate-authority-common]
requests-directory = ${directory:ca-requests}
ca-dir = ${directory:ca-dir}
ca-private = ${directory:ca-private}
ca-certs = ${directory:ca-certs}
ca-newcerts = ${directory:ca-newcerts}
ca-crl = ${directory:ca-crl}
[{{ section('certificate-authority') }}]
< = certificate-authority-common
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${binary-link:target-directory}/openssl
wrapper = ${directory:services}/ca
{% if use_ipv6 -%}
{% set ipv6 = (ipv6_set | list)[0] -%}
......@@ -479,8 +443,8 @@ wrapper-path = ${buildout:bin-directory}/runTestSuite
< = run-common
environment-extra =
REAL_INSTANCE_HOME=${:instance-home}
OPENSSL_BINARY=${test-certificate-authority:openssl-binary}
TEST_CA_PATH=${test-certificate-authority:ca-dir}
OPENSSL_BINARY={{ openssl_bin }}/openssl
TEST_CA_PATH=${directory:ca-dir}
instance-home = ${directory:unit-test-path}
wrapper-path = ${directory:bin}/${:command-name}.real
command-line =
......@@ -561,5 +525,5 @@ extends =
{{ logrotate_cfg }}
{{ parameter_dict['template-monitor'] }}
parts +=
{{ part_list | join('\n ') }}
{{ '\n '.join(part_list) }}
publish
[buildout]
extends =
{{ instance_common_cfg }}
{{ caucase_template }}
[jinja2-template-base]
mode = 644
......@@ -35,6 +34,10 @@ jupyter-enable-default = {{ jupyter_enable_default }}
local-bt5-repository = {{ ' '.join(local_bt5_repository.split()) }}
template-monitor = {{ dumps(template_monitor) }}
[context]
root-common = {{ root_common }}
caucase-jinja2-library = {{ caucase_jinja2_library }}
[dynamic-template-erp5]
<= jinja2-template-base
template = {{ template_erp5 }}
......@@ -47,7 +50,8 @@ extra-context =
key openssl_location :openssl-location
import urlparse urlparse
import-list =
rawfile root_common {{ root_common }}
file root_common context:root-common
file caucase context:caucase-jinja2-library
openssl-location = {{ openssl_location }}
......@@ -70,6 +74,8 @@ filename = instance-balancer.cfg
extra-context =
section parameter_dict dynamic-template-balancer-parameters
import itertools itertools
import-list =
file caucase context:caucase-jinja2-library
[dynamic-template-zeo-parameters]
<= default-dynamic-template-parameters
......@@ -112,6 +118,7 @@ extra-context =
import urlparse urlparse
import hashlib hashlib
import itertools itertools
raw openssl_bin {{ openssl_location}}/bin
[dynamic-template-kumofs-parameters]
<= default-dynamic-template-parameters
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment