From 27b8529047df690a0152842429a0c30b891f7aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20de=20Saint=20Martin?= <cedric.dsm@tiolive.com> Date: Mon, 6 Jun 2011 20:38:31 +0200 Subject: [PATCH] Kumofs : add stunnel --- slapos/recipe/kumofs/__init__.py | 16 +- slapos/recipe/kumofs/certificate_authority.py | 112 ++++++ .../recipe/kumofs/template/openssl.cnf.ca.in | 350 ++++++++++++++++++ slapos/recipe/kumofs/template/stunnel.conf.in | 14 + software/kumofs/instance.cfg | 7 +- software/kumofs/software.cfg | 4 + 6 files changed, 500 insertions(+), 3 deletions(-) create mode 100644 slapos/recipe/kumofs/certificate_authority.py create mode 100644 slapos/recipe/kumofs/template/openssl.cnf.ca.in create mode 100644 slapos/recipe/kumofs/template/stunnel.conf.in diff --git a/slapos/recipe/kumofs/__init__.py b/slapos/recipe/kumofs/__init__.py index f4ccf6f16..c8c341c52 100644 --- a/slapos/recipe/kumofs/__init__.py +++ b/slapos/recipe/kumofs/__init__.py @@ -37,11 +37,23 @@ class Recipe(BaseSlapRecipe): def _install(self): self.path_list = [] + self.requirements, self.ws = self.egg.working_set() # XXX-Cedric : add logrotate? - kumo_conf = self.installKumo(self.getGlobalIPv6Address()) + kumo_conf = self.installKumo(self.getLocalIPv4Address()) + + ca_conf = self.installCertificateAuthority() + key, certificate = self.requestCertificate('Login Based Access') + + stunnel_conf = self.installStunnel(self.getGlobalIPv6Address(), 12345, + kumo_conf_conf['kumo_gateway_port'], + certificate, key, ca_conf['ca_crl'], + ca_conf['certificate_authority_path']) + self.linkBinary() self.setConnectionDict(dict( - address = kumo_conf['kumo_address'], + kumofs_local_ip = kumo_conf['kumo_gateway_ip'], + stunnel_ip = stunnel_conf['ip'], + stunnel_port = stunnel_conf['port'], )) return self.path_list diff --git a/slapos/recipe/kumofs/certificate_authority.py b/slapos/recipe/kumofs/certificate_authority.py new file mode 100644 index 000000000..8caffc0c2 --- /dev/null +++ b/slapos/recipe/kumofs/certificate_authority.py @@ -0,0 +1,112 @@ +import os +import subprocess +import time +import ConfigParser + + +def popenCommunicate(command_list, input=None): + subprocess_kw = dict(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + if input is not None: + subprocess_kw.update(stdin=subprocess.PIPE) + popen = subprocess.Popen(command_list, **subprocess_kw) + result = popen.communicate(input)[0] + if popen.returncode is None: + popen.kill() + if popen.returncode != 0: + raise ValueError('Issue during calling %r, result was:\n%s' % ( + command_list, result)) + return result + + +class CertificateAuthority: + def __init__(self, key, certificate, openssl_binary, + openssl_configuration, request_dir): + self.key = key + self.certificate = certificate + self.openssl_binary = openssl_binary + self.openssl_configuration = openssl_configuration + self.request_dir = request_dir + + def checkAuthority(self): + file_list = [ self.key, self.certificate ] + ca_ready = True + for f in file_list: + if not os.path.exists(f): + ca_ready = False + break + if ca_ready: + return + for f in file_list: + if os.path.exists(f): + os.unlink(f) + try: + # no CA, let us create new one + popenCommunicate([self.openssl_binary, 'req', '-nodes', '-config', + self.openssl_configuration, '-new', '-x509', '-extensions', + 'v3_ca', '-keyout', self.key, '-out', self.certificate, + '-days', '10950'], 'Automatic Certificate Authority\n') + except: + try: + for f in file_list: + if os.path.exists(f): + os.unlink(f) + except: + # do not raise during cleanup + pass + raise + + def _checkCertificate(self, common_name, key, certificate): + file_list = [key, certificate] + ready = True + for f in file_list: + if not os.path.exists(f): + ready = False + break + if ready: + return False + for f in file_list: + if os.path.exists(f): + os.unlink(f) + csr = certificate + '.csr' + try: + popenCommunicate([self.openssl_binary, 'req', '-config', + self.openssl_configuration, '-nodes', '-new', '-keyout', + key, '-out', csr, '-days', '3650'], + common_name + '\n') + try: + popenCommunicate([self.openssl_binary, 'ca', '-batch', '-config', + self.openssl_configuration, '-out', certificate, + '-infiles', csr]) + finally: + if os.path.exists(csr): + os.unlink(csr) + except: + try: + for f in file_list: + if os.path.exists(f): + os.unlink(f) + except: + # do not raise during cleanup + pass + raise + else: + return True + + def checkRequestDir(self): + for request_file in os.listdir(self.request_dir): + parser = ConfigParser.RawConfigParser() + parser.readfp(open(os.path.join(self.request_dir, request_file), 'r')) + if self._checkCertificate(parser.get('certificate', 'name'), + parser.get('certificate', 'key_file'), parser.get('certificate', + 'certificate_file')): + print 'Created certificate %r' % parser.get('certificate', 'name') + +def runCertificateAuthority(args): + ca_conf = args[0] + ca = CertificateAuthority(ca_conf['key'], ca_conf['certificate'], + ca_conf['openssl_binary'], ca_conf['openssl_configuration'], + ca_conf['request_dir']) + while True: + ca.checkAuthority() + ca.checkRequestDir() + time.sleep(60) diff --git a/slapos/recipe/kumofs/template/openssl.cnf.ca.in b/slapos/recipe/kumofs/template/openssl.cnf.ca.in new file mode 100644 index 000000000..8a450a687 --- /dev/null +++ b/slapos/recipe/kumofs/template/openssl.cnf.ca.in @@ -0,0 +1,350 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = %(working_directory)s # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem # The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 3650 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_md = sha1 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +#attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_value = %(country_code)s +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_value = %(state)s + +localityName = Locality Name (eg, city) +localityName_value = %(city)s + +0.organizationName = Organization Name (eg, company) +0.organizationName_value = %(company)s + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +commonName = Common Name (eg, your name or your server\'s hostname) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_value = %(email_address)s +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +#[ req_attributes ] +#challengePassword = A challenge password +#challengePassword_min = 4 +#challengePassword_max = 20 +# +#unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = /etc/pki/tls # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) + +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = md5, sha1 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) diff --git a/slapos/recipe/kumofs/template/stunnel.conf.in b/slapos/recipe/kumofs/template/stunnel.conf.in new file mode 100644 index 000000000..3be30f46b --- /dev/null +++ b/slapos/recipe/kumofs/template/stunnel.conf.in @@ -0,0 +1,14 @@ +foreground = yes +output = %(log)s +pid = %(pid_file)s +syslog = no +;accept = %(ip)s%(port)s +CApath = %(ca_path)s +key = %(key)s +CRLpath = %(ca_crl)s +cert = %(cert)s +;key = /etc/ssl/certs/stunnel.pem + +[mysqls] +accept = %(ipv6)s:%(port)s +connect = %(ipv4)s:%(external_port)s diff --git a/software/kumofs/instance.cfg b/software/kumofs/instance.cfg index bd6e923b1..8d7a6a434 100644 --- a/software/kumofs/instance.cfg +++ b/software/kumofs/instance.cfg @@ -9,4 +9,9 @@ develop-eggs-directory = ${buildout:develop-eggs-directory} recipe = ${instance-recipe:egg}:${instance-recipe:module} kumo_gateway_binary = ${kumo:location}/bin/kumo-gateway kumo_manager_binary = ${kumo:location}/bin/kumo-manager -kumo_server_binary = ${kumo:location}/bin/kumo-server \ No newline at end of file +kumo_server_binary = ${kumo:location}/bin/kumo-server +dcrond_binary = ${dcron:location}/sbin/crond +innobackupex_binary = ${xtrabackup:location}/bin/innobackupex +openssl_binary = ${openssl:location}/bin/openssl +rdiff_backup_binary = ${buildout:bin-directory}/rdiff-backup +stunnel_binary = ${stunnel:location}/bin/stunnel diff --git a/software/kumofs/software.cfg b/software/kumofs/software.cfg index 91bb147b0..b5fafe2cf 100644 --- a/software/kumofs/software.cfg +++ b/software/kumofs/software.cfg @@ -15,6 +15,10 @@ extends = ../../component/git/buildout.cfg ../../component/kumo/buildout.cfg ../../component/python-2.7/buildout.cfg + ../../component/dcron/buildout.cfg + ../../component/stunnel/buildout.cfg + ../../component/python-2.7/buildout.cfg + ../../component/rdiff-backup/buildout.cfg versions = versions -- 2.30.9