Commit d0dc448b authored by Dimitris Aragiorgis's avatar Dimitris Aragiorgis
Browse files

deploy: Workaround for cert_override.txt

For cyclades, pithos, astakos, and cms use firefox_cert_override.py
script (credits to kpap@grnet.gr) to manually create proper entries
so that the end user running firefox does not have to accept all
certificates before having a working environment.

This will add /etc/iceweasel/profile/cert_override.txt on client
node with entries for:

astakos.synnefo.live:443
cyclades.synnefo.live:443
pithos.synnefo.live:443
cms.synnefo.live:443
synnefo.live:443

and the corresponding IPs (currently needed for cyclades UI).

For further info about cert_override.txt file see:

https://developer.mozilla.org/en-US/docs/Cert_override.txt

Signed-off-by: default avatarDimitris Aragiorgis <dimara@grnet.gr>
parent a6428d20
# Copyright (C) 2010-2014 GRNET S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import OpenSSL
import sys
import base64
def cert_override(cert_contents, domain):
"""
Generate a certificate exception entry. The result can be appended in
`cert_override.txt`.
https://developer.mozilla.org/en-US/docs/Cert_override.txt
"""
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
cert_contents)
tpl = "%(domain)s\t%(oid)s\t%(cert_hash)s" + \
"\t%(options)s\t%(serial_hash)s\t%(issuer_hash)s"
oid = "OID.2.16.840.1.101.3.4.2.1"
cert_hash = cert.digest("sha256")
options = "MU"
serial = ("%x" % cert.get_serial_number()).decode("hex")
issuer_parts = cert.get_issuer().der().split(".")
issuer_name = "".join(issuer_parts[:-2])
issuer_domain = ".".join(issuer_parts[-2:])
serial_prefix = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t" + \
"\x00\x00\x00$\x00"
serial_content = serial_prefix + serial + issuer_name
serial_hash = base64.b64encode(serial_content)
issuer_hash = base64.b64encode(issuer_domain)
return tpl % {
'domain': domain,
'oid': oid,
'cert_hash': cert_hash,
'options': options,
'serial_hash': serial_hash,
'issuer_hash': issuer_hash
}
if __name__ == "__main__":
try:
cert_path, domain = sys.argv[1], sys.argv[2]
except IndexError:
print "Usage: %s <cert_path> <domain>" % (sys.argv[0])
exit(1)
print cert_override(file(cert_path).read(), domain)
......@@ -122,6 +122,7 @@ def update_admin(fn):
cl.DB = DB(node=ctx.db.node, ctx=ctx)
cl.ASTAKOS = Astakos(node=ctx.astakos.node, ctx=ctx)
cl.CYCLADES = Cyclades(node=ctx.cyclades.node, ctx=ctx)
cl.CLIENT = Client(node=ctx.client.node, ctx=ctx)
return fn(*args, **kwargs)
return wrapper
......@@ -159,6 +160,26 @@ def export_and_import_service(fn):
return wrapper
def cert_override(fn):
""" Create all needed entries for cert_override.txt file
Append them in a tmp file and upload them to client node
"""
def wrapper(*args, **kwargs):
cl = args[0]
f = "/tmp/" + constants.CERT_OVERRIDE + "_" + cl.service
for domain in [cl.node.domain, cl.node.cname, cl.node.ip]:
cmd = """
python /root/firefox_cert_override.py {0} {1}:443 >> {2}
""".format(constants.CERT_PATH, domain, f)
cl.run(cmd)
cl.get(f, f + ".local")
cl.CLIENT.put(f + ".local", f)
return fn(*args, **kwargs)
return wrapper
# ########################## Components ############################
# A Component() gets initialized with an execution context that is a
......@@ -890,9 +911,11 @@ class Astakos(base.Component):
"python-django-south",
"snf-astakos-app",
"kamaki",
"python-openssl",
]
alias = constants.ASTAKOS
service = constants.ASTAKOS
def required_components(self):
return [HW, SSH, DNS, APT, Apache, Gunicorn, Common, WEB]
......@@ -996,7 +1019,8 @@ class Astakos(base.Component):
"PITHOS": self.ctx.pithos.cname,
}
return [
("/etc/synnefo/astakos.conf", r1, {})
("/etc/synnefo/astakos.conf", r1, {}),
("/root/firefox_cert_override.py", {}, {})
]
@base.run_cmds
......@@ -1054,6 +1078,7 @@ class Astakos(base.Component):
@update_admin
@export_and_import_service
@cert_override
def admin_post(self):
self.set_astakos_default_quota()
......@@ -1061,9 +1086,11 @@ class Astakos(base.Component):
class CMS(base.Component):
REQUIRED_PACKAGES = [
"snf-cloudcms"
"python-openssl",
]
alias = constants.CMS
service = constants.CMS
def required_components(self):
return [HW, SSH, DNS, APT, Apache, Gunicorn, Common, WEB]
......@@ -1106,6 +1133,11 @@ class CMS(base.Component):
def restart(self):
return ["/etc/init.d/gunicorn restart"]
@update_admin
@cert_override
def admin_post(self):
pass
class Mount(base.Component):
REQUIRED_PACKAGES = [
......@@ -1192,6 +1224,7 @@ class Pithos(base.Component):
"python-svipc",
"snf-pithos-app",
"snf-pithos-webclient",
"python-openssl",
]
alias = constants.PITHOS
......@@ -1240,6 +1273,7 @@ class Pithos(base.Component):
return [
("/etc/synnefo/pithos.conf", r1, {}),
("/etc/synnefo/webclient.conf", r2, {}),
("/root/firefox_cert_override.py", {}, {})
]
@base.run_cmds
......@@ -1254,6 +1288,7 @@ class Pithos(base.Component):
@update_admin
@export_and_import_service
@cert_override
def admin_post(self):
self.ASTAKOS.set_pithos_default_quota()
......@@ -1283,6 +1318,7 @@ class Cyclades(base.Component):
"kamaki",
"snf-cyclades-app",
"python-django-south",
"python-openssl",
]
alias = constants.CYCLADES
......@@ -1388,7 +1424,8 @@ snf-manage network-create --subnet6={0} \
"CYCLADES_NODE_IP": self.ctx.cyclades.ip
}
return [
("/etc/synnefo/cyclades.conf", r1, {})
("/etc/synnefo/cyclades.conf", r1, {}),
("/root/firefox_cert_override.py", {}, {})
]
@base.run_cmds
......@@ -1415,6 +1452,7 @@ snf-manage network-create --subnet6={0} \
@update_admin
@export_and_import_service
@cert_override
def admin_post(self):
self.ASTAKOS.set_cyclades_default_quota()
......@@ -1646,7 +1684,7 @@ class Client(base.Component):
alias = constants.CLIENT
def required_components(self):
return [HW, SSH, DNS, APT, Kamaki, Burnin]
return [HW, SSH, DNS, APT, Kamaki, Burnin, Firefox]
class GanetiDev(base.Component):
......@@ -1779,3 +1817,16 @@ class Router(base.Component):
REQUIRED_PACKAGES = [
"iptables"
]
class Firefox(base.Component):
REQUIRED_PACKAGES = [
"iceweasel",
]
@base.run_cmds
def initialize(self):
f = constants.CERT_OVERRIDE
return [
"cat /tmp/%s_* >> /etc/iceweasel/profile/%s" % (f, f)
]
......@@ -36,3 +36,6 @@ STATUS_FILE = "snf_deploy_status"
DEFAULT_NODE = "node1"
DEFAULT_CLUSTER = "ganeti1"
DEFAULT_SETUP = "synnefo"
CERT_OVERRIDE = "cert_override.txt"
CERT_PATH = "/etc/ssl/certs/ssl-cert-snakeoil.pem"
......@@ -65,6 +65,7 @@ class Context(object):
self.stats = self.get(constants.STATS)
self.cms = self.get(constants.CMS)
self.router = self.get(constants.ROUTER)
self.client = self.get(constants.CLIENT)
def get(self, role):
return config.get_single_node_role_info(self.setup, role)
......
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