mirror of
				https://github.com/laurivosandi/certidude
				synced 2025-10-31 01:19:11 +00:00 
			
		
		
		
	Fixes
This commit is contained in:
		| @@ -29,9 +29,9 @@ class LeaseResource(object): | ||||
|         # TODO: verify signature | ||||
|         common_name = req.get_param("client", required=True) | ||||
|         path, buf, cert = authority.get_signed(common_name) # TODO: catch exceptions | ||||
|         if cert.serial != req.get_param_as_int("serial", required=True): # Badum we have OCSP! | ||||
|             raise # TODO proper exception | ||||
|         if req.get_param("action") == "client-connect": | ||||
|         if cert.serial != req.get_param_as_int("serial"): # OCSP-ish solution for OpenVPN, not exposed for StrongSwan | ||||
|             raise falcon.HTTPForbidden("Forbidden", "Invalid serial number supplied") | ||||
|  | ||||
|         xattr.setxattr(path, "user.lease.address", req.get_param("address", required=True).encode("ascii")) | ||||
|         xattr.setxattr(path, "user.lease.last_seen", datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z") | ||||
|         push.publish("lease-update", common_name) | ||||
|   | ||||
| @@ -15,8 +15,7 @@ import subprocess | ||||
| import sys | ||||
| from configparser import ConfigParser, NoOptionError, NoSectionError | ||||
| from certidude.helpers import certidude_request_certificate | ||||
| from certidude.common import expand_paths, ip_address, ip_network | ||||
| from certidude.decorators import apt, rpm, pip | ||||
| from certidude.common import expand_paths, ip_address, ip_network, apt, rpm, pip | ||||
| from cryptography import x509 | ||||
| from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID | ||||
| from cryptography.hazmat.backends import default_backend | ||||
| @@ -39,28 +38,6 @@ env = Environment(loader=PackageLoader("certidude", "templates"), trim_blocks=Tr | ||||
|  | ||||
| NOW = datetime.utcnow().replace(tzinfo=None) | ||||
|  | ||||
| CERTIDUDE_TIMER = """ | ||||
| [Unit] | ||||
| Description=Run certidude service weekly | ||||
|  | ||||
| [Timer] | ||||
| OnCalendar=weekly | ||||
| Persistent=true | ||||
| Unit=certidude.service | ||||
|  | ||||
| [Install] | ||||
| WantedBy=timers.target | ||||
| """ | ||||
|  | ||||
| CERTIDUDE_SERVICE = """ | ||||
| [Unit] | ||||
| Description=Renew certificates and update revocation lists | ||||
|  | ||||
| [Service] | ||||
| Type=simple | ||||
| ExecStart=%s request | ||||
| """ | ||||
|  | ||||
| @click.command("request", help="Run processes for requesting certificates and configuring services") | ||||
| @click.option("-r", "--renew", default=False, is_flag=True, help="Renew now") | ||||
| @click.option("-f", "--fork", default=False, is_flag=True, help="Fork to background") | ||||
| @@ -88,15 +65,17 @@ def certidude_request(fork, renew): | ||||
|     if not os.path.exists(run_dir): | ||||
|         click.echo("Creating: %s" % run_dir) | ||||
|         os.makedirs(run_dir) | ||||
|     context = globals() | ||||
|     context.update(locals()) | ||||
|  | ||||
|     if not os.path.exists("/etc/systemd/system/certidude.timer"): | ||||
|         click.echo("Creating systemd timer...") | ||||
|         with open("/etc/systemd/system/certidude.timer", "w") as fh: | ||||
|             fh.write(CERTIDUDE_TIMER) | ||||
|             fh.write(env.get_template("client/certidude.timer").render(context)) | ||||
|     if not os.path.exists("/etc/systemd/system/certidude.service"): | ||||
|         click.echo("Creating systemd service...") | ||||
|         with open("/etc/systemd/system/certidude.service", "w") as fh: | ||||
|             fh.write(CERTIDUDE_SERVICE % sys.argv[0]) | ||||
|             fh.write(env.get_template("client/certidude.service").render(context)) | ||||
|  | ||||
|  | ||||
|     for authority in clients.sections(): | ||||
| @@ -364,6 +343,9 @@ def certidude_request(fork, renew): | ||||
|     type=click.File(mode="w", atomic=True, lazy=True), | ||||
|     help="OpenVPN configuration file") | ||||
| def certidude_setup_openvpn_server(authority, config, subnet, route, local, proto, port): | ||||
|     # Install dependencies | ||||
|     apt("openvpn") | ||||
|     rpm("openvpn") | ||||
|  | ||||
|     # Create corresponding section in Certidude client configuration file | ||||
|     client_config = ConfigParser() | ||||
| @@ -506,9 +488,10 @@ def certidude_setup_nginx(authority, site_config, tls_config, common_name, direc | ||||
|     default="/etc/openvpn/client-to-site.conf", | ||||
|     type=click.File(mode="w", atomic=True, lazy=True), | ||||
|     help="OpenVPN configuration file") | ||||
| @apt("openvpn python-requests-kerberos") | ||||
| @rpm("openvpn python2-requests-kerberos") | ||||
| def certidude_setup_openvpn_client(authority, remote, config, proto): | ||||
|     # Install dependencies | ||||
|     apt("openvpn") | ||||
|     rpm("openvpn") | ||||
|  | ||||
|     # Create corresponding section in Certidude client configuration file | ||||
|     client_config = ConfigParser() | ||||
| @@ -531,7 +514,7 @@ def certidude_setup_openvpn_client(authority, remote, config, proto): | ||||
|         click.echo("Section '%s' added to %s" % (authority, const.CLIENT_CONFIG_PATH)) | ||||
|  | ||||
|     # Create corresponding section in /etc/certidude/services.conf | ||||
|     endpoint = "OpenVPN connection to %s" % remote | ||||
|     endpoint = "OpenVPN to %s" % remote | ||||
|     service_config = ConfigParser() | ||||
|     if os.path.exists(const.SERVICES_CONFIG_PATH): | ||||
|         service_config.readfp(open(const.SERVICES_CONFIG_PATH)) | ||||
| @@ -574,13 +557,15 @@ def certidude_setup_openvpn_client(authority, remote, config, proto): | ||||
| @click.option("--common-name", "-cn", default=const.FQDN, help="Common name, %s by default" % const.FQDN) | ||||
| @click.option("--subnet", "-sn", default=u"192.168.33.0/24", type=ip_network, help="IPsec virtual subnet, 192.168.33.0/24 by default") | ||||
| @click.option("--route", "-r", type=ip_network, multiple=True, help="Subnets to advertise via this connection, multiple allowed") | ||||
| @apt("strongswan python-requests python-requests-kerberos") | ||||
| @rpm("strongswan python2-requests python2-requests-kerberos") | ||||
| @pip("ipsecparse") | ||||
| def certidude_setup_strongswan_server(authority, common_name, subnet, route): | ||||
|     if "." not in common_name: | ||||
|         raise ValueError("Hostname has to be fully qualified!") | ||||
|  | ||||
|     # Install dependencies | ||||
|     apt("strongswan") | ||||
|     rpm("strongswan") | ||||
|     pip("ipsecparse") | ||||
|  | ||||
|     # Create corresponding section in Certidude client configuration file | ||||
|     client_config = ConfigParser() | ||||
|     if os.path.exists(const.CLIENT_CONFIG_PATH): | ||||
| @@ -605,14 +590,10 @@ def certidude_setup_strongswan_server(authority, common_name, subnet, route): | ||||
|     from ipsecparse import loads | ||||
|     config = loads(open("%s/ipsec.conf" % const.STRONGSWAN_PREFIX).read()) | ||||
|     config["conn", authority] = dict( | ||||
|         leftsourceip="%config", | ||||
|         left=common_name, | ||||
|         leftcert=client_config.get(authority, "certificate path"), | ||||
|         leftsubnet=",".join(route), | ||||
|         right="%any", | ||||
|         rightsourceip=str(subnet), | ||||
|         keyexchange="ikev2", | ||||
|         keyingtries="300", | ||||
|         closeaction="restart", | ||||
|         auto="ignore") | ||||
|     with open("%s/ipsec.conf.part" % const.STRONGSWAN_PREFIX, "w") as fh: | ||||
| @@ -629,10 +610,12 @@ def certidude_setup_strongswan_server(authority, common_name, subnet, route): | ||||
| @click.command("client", help="Set up strongSwan client") | ||||
| @click.argument("authority") | ||||
| @click.argument("remote") | ||||
| @apt("strongswan python-requests python-requests-kerberos") | ||||
| @rpm("strongswan python2-requests python2-requests-kerberos") | ||||
| @pip("ipsecparse") | ||||
| def certidude_setup_strongswan_client(authority, remote): | ||||
|     # Install dependencies | ||||
|     apt("strongswan") | ||||
|     rpm("strongswan") | ||||
|     pip("ipsecparse") | ||||
|  | ||||
|     # Create corresponding section in /etc/certidude/client.conf | ||||
|     client_config = ConfigParser() | ||||
|     if os.path.exists(const.CLIENT_CONFIG_PATH): | ||||
| @@ -698,9 +681,11 @@ def certidude_setup_strongswan_client(authority, remote): | ||||
| @click.command("networkmanager", help="Set up strongSwan client via NetworkManager") | ||||
| @click.argument("authority") # Certidude server | ||||
| @click.argument("remote") # StrongSwan gateway | ||||
| @apt("strongswan-nm python-requests python-requests-kerberos") | ||||
| @rpm("NetworkManager-strongswan-gnome python2-requests python2-requests-kerberos") | ||||
| def certidude_setup_strongswan_networkmanager(authority, remote): | ||||
|     # Install dependencies | ||||
|     apt("strongswan-nm") | ||||
|     rpm("NetworkManager-strongswan-gnome") | ||||
|  | ||||
|     endpoint = "IPSec to %s" % remote | ||||
|  | ||||
|     # Create corresponding section in /etc/certidude/client.conf | ||||
| @@ -799,11 +784,13 @@ def certidude_setup_openvpn_networkmanager(authority, remote): | ||||
| @click.option("--directory", help="Directory for authority files") | ||||
| @click.option("--server-flags", is_flag=True, help="Add TLS Server and IKE Intermediate extended key usage flags") | ||||
| @click.option("--outbox", default="smtp://smtp.%s" % const.DOMAIN, help="SMTP server, smtp://smtp.%s by default" % const.DOMAIN) | ||||
| @apt("python-setproctitle python-openssl python-falcon python-humanize python-markdown python-xattr") | ||||
| @rpm("python-setproctitle pyOpenSSL python-falcon python-humanize python-markdown pyxattr") | ||||
| def certidude_setup_authority(username, kerberos_keytab, nginx_config, country, state, locality, organization, organizational_unit, common_name, directory, authority_lifetime, push_server, outbox, server_flags): | ||||
|     openvpn_profile_template_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates", "openvpn-client.conf") | ||||
|     bootstrap_template_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates", "bootstrap.conf") | ||||
|     # Install dependencies | ||||
|     apt("python-setproctitle python-openssl python-falcon python-humanize python-markdown python-xattr") | ||||
|     rpm("python-setproctitle pyOpenSSL python-falcon python-humanize python-markdown pyxattr") | ||||
|     pip("gssapi") | ||||
|  | ||||
|     template_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates") | ||||
|  | ||||
|     if not directory: | ||||
|         if os.getuid(): | ||||
| @@ -848,7 +835,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, country, | ||||
|             base = ",".join(["dc=" + j for j in domain.split(".")]) | ||||
|             if not os.path.exists("/etc/cron.hourly/certidude"): | ||||
|                 with open("/etc/cron.hourly/certidude", "w") as fh: | ||||
|                     fh.write(env.get_template("ldap-ticket-renewal.sh").render(vars())) | ||||
|                     fh.write(env.get_template("server/cronjob").render(vars())) | ||||
|                 os.chmod("/etc/cron.hourly/certidude", 0o755) | ||||
|                 click.echo("Created /etc/cron.hourly/certidude for automatic LDAP service ticket renewal, inspect and adjust accordingly") | ||||
|             os.system("/etc/cron.hourly/certidude") | ||||
| @@ -865,7 +852,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, country, | ||||
|             port = "80" | ||||
|         else: | ||||
|             port = "8080" | ||||
|             nginx_config.write(env.get_template("nginx.conf").render(vars())) | ||||
|             nginx_config.write(env.get_template("server/nginx.conf").render(vars())) | ||||
|             click.echo("Generated: %s" % nginx_config.name) | ||||
|             if not os.path.exists("/etc/nginx/sites-enabled/certidude.conf"): | ||||
|                 os.symlink("../sites-available/certidude.conf", "/etc/nginx/sites-enabled/certidude.conf") | ||||
| @@ -880,7 +867,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, country, | ||||
|                 click.echo("File /etc/systemd/system/certidude.service already exists, remove to regenerate") | ||||
|             else: | ||||
|                 with open("/etc/systemd/system/certidude.service", "w") as fh: | ||||
|                     fh.write(env.get_template("systemd.service").render(vars())) | ||||
|                     fh.write(env.get_template("server/systemd.service").render(vars())) | ||||
|                 click.echo("File /etc/systemd/system/certidude.service created") | ||||
|         else: | ||||
|             NotImplemented # No systemd | ||||
| @@ -900,7 +887,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, country, | ||||
|         os.umask(0o137) | ||||
|         push_token = "".join([random.choice(string.ascii_letters + string.digits) for j in range(0,32)]) | ||||
|         with open(const.CONFIG_PATH, "w") as fh: | ||||
|             fh.write(env.get_template("certidude-server.conf").render(vars())) | ||||
|             fh.write(env.get_template("server/server.conf").render(vars())) | ||||
|         click.echo("Generated %s" % const.CONFIG_PATH) | ||||
|  | ||||
|     if os.path.lexists(directory): | ||||
|   | ||||
| @@ -35,3 +35,29 @@ def expand_paths(): | ||||
|         return wrapped | ||||
|     return wrapper | ||||
|  | ||||
|  | ||||
| def apt(packages): | ||||
|     """ | ||||
|     Install packages for Debian and Ubuntu | ||||
|     """ | ||||
|     if os.path.exists("/usr/bin/apt-get"): | ||||
|         cmd = ["/usr/bin/apt-get", "install", "-yqq"] + packages.split(" ") | ||||
|         click.echo("Running: %s" % " ".join(cmd)) | ||||
|         subprocess.call(cmd) | ||||
|  | ||||
|  | ||||
| def rpm(packages): | ||||
|     """ | ||||
|     Install packages for Fedora and CentOS | ||||
|     """ | ||||
|     if os.path.exists("/usr/bin/dnf"): | ||||
|         cmd = ["/usr/bin/dnf", "install", "-y"] + packages.split(" ") | ||||
|         click.echo("Running: %s" % " ".join(cmd)) | ||||
|         subprocess.call(cmd) | ||||
|  | ||||
|  | ||||
| def pip(packages): | ||||
|     click.echo("Running: pip install %s" % packages) | ||||
|     import pip | ||||
|     pip.main(['install'] + packages.split(" ")) | ||||
|  | ||||
|   | ||||
| @@ -74,6 +74,11 @@ EVENT_SOURCE_SUBSCRIBE = cp.get("push", "event source subscribe") | ||||
| LONG_POLL_PUBLISH = cp.get("push", "long poll publish") | ||||
| LONG_POLL_SUBSCRIBE = cp.get("push", "long poll subscribe") | ||||
|  | ||||
| if os.getenv("TRAVIS"): # TODO: include nginx setup in Travis | ||||
|     EVENT_SOURCE_PUBLISH = "" | ||||
|     LONG_POLL_PUBLISH = "" | ||||
|     LONG_POLL_SUBSCRIBE = "" | ||||
|  | ||||
| LOGGING_BACKEND = cp.get("logging", "backend") | ||||
|  | ||||
| if "whitelist" == AUTHORIZATION_BACKEND: | ||||
|   | ||||
| @@ -88,43 +88,3 @@ def serialize(func): | ||||
|         resp.body = json.dumps(func(instance, req, resp, **kwargs), cls=MyEncoder) | ||||
|     return wrapped | ||||
|  | ||||
|  | ||||
| def apt(packages): | ||||
|     """ | ||||
|     Install packages for Debian and Ubuntu | ||||
|     """ | ||||
|     def wrapper(func): | ||||
|         def wrapped(*args, **kwargs): | ||||
|             if os.path.exists("/usr/bin/apt-get"): | ||||
|                 cmd = ["/usr/bin/apt-get", "install", "-yqq"] + packages.split(" ") | ||||
|                 click.echo("Running: %s" % " ".join(cmd)) | ||||
|                 subprocess.call(cmd) | ||||
|             return func(*args, **kwargs) | ||||
|         return wrapped | ||||
|     return wrapper | ||||
|  | ||||
|  | ||||
| def rpm(packages): | ||||
|     """ | ||||
|     Install packages for Fedora and CentOS | ||||
|     """ | ||||
|     def wrapper(func): | ||||
|         def wrapped(*args, **kwargs): | ||||
|             if os.path.exists("/usr/bin/dnf"): | ||||
|                 cmd = ["/usr/bin/dnf", "install", "-y"] + packages.split(" ") | ||||
|                 click.echo("Running: %s" % " ".join(cmd)) | ||||
|                 subprocess.call(cmd) | ||||
|             return func(*args, **kwargs) | ||||
|         return wrapped | ||||
|     return wrapper | ||||
|  | ||||
|  | ||||
| def pip(packages): | ||||
|     def wrapper(func): | ||||
|         def wrapped(*args, **kwargs): | ||||
|             click.echo("Running: pip install %s" % packages) | ||||
|             import pip | ||||
|             pip.main(['install'] + packages.split(" ")) | ||||
|             return func(*args, **kwargs) | ||||
|         return wrapped | ||||
|     return wrapper | ||||
|   | ||||
							
								
								
									
										6
									
								
								certidude/templates/client/certidude.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								certidude/templates/client/certidude.service
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| [Unit] | ||||
| Description=Renew certificates and update revocation lists | ||||
|  | ||||
| [Service] | ||||
| Type=simple | ||||
| ExecStart={{ sys.argv[0] }} request | ||||
							
								
								
									
										11
									
								
								certidude/templates/client/certidude.timer
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								certidude/templates/client/certidude.timer
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| [Unit] | ||||
| Description=Run certidude service weekly | ||||
|  | ||||
| [Timer] | ||||
| OnCalendar=weekly | ||||
| Persistent=true | ||||
| Unit=certidude.service | ||||
|  | ||||
| [Install] | ||||
| WantedBy=timers.target | ||||
|  | ||||
| @@ -142,7 +142,7 @@ format = p12 | ||||
| 
 | ||||
| # Template for OpenVPN profile, copy certidude/templates/openvpn-client.conf | ||||
| # to /etc/certidude/ and make modifications as necessary | ||||
| openvpn profile template = {{ openvpn_profile_template_path }} | ||||
| openvpn profile template = {{ template_path }}/openvpn-client.conf | ||||
| 
 | ||||
| [tagging] | ||||
| owner/string = Owner | ||||
| @@ -154,4 +154,4 @@ other/ = Other | ||||
| # Following can be used to set up clients easily: certidude bootstrap ca.example.lan | ||||
| # Services template is rendered on certidude server with relevant variables and | ||||
| # placed to /etc/certidude/services.conf on the client | ||||
| services template = {{ bootstrap_template_path }} | ||||
| services template = {{ template_path }}/bootstrap.conf | ||||
		Reference in New Issue
	
	Block a user