mirror of
				https://github.com/laurivosandi/certidude
				synced 2025-10-31 17:39:12 +00:00 
			
		
		
		
	Grand unified snippets
This commit is contained in:
		
							
								
								
									
										27
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								README.rst
									
									
									
									
									
								
							| @@ -60,7 +60,7 @@ Features | |||||||
| Common: | Common: | ||||||
|  |  | ||||||
| * Standard request, sign, revoke workflow via web interface. | * Standard request, sign, revoke workflow via web interface. | ||||||
| * RSA and Elliptic Curve Cryptography both supported, use ``certidude setup authority --elliptic-curve`` for the second | * RSA and Elliptic Curve Cryptography both supported, use ``certidude provision authority --elliptic-curve`` for the second | ||||||
| * `OCSP <https://tools.ietf.org/html/rfc4557>`_ and `SCEP <https://tools.ietf.org/html/draft-nourse-scep-23>`_ support. | * `OCSP <https://tools.ietf.org/html/rfc4557>`_ and `SCEP <https://tools.ietf.org/html/draft-nourse-scep-23>`_ support. | ||||||
| * PAM and Active Directory compliant authentication backends: Kerberos single sign-on, LDAP simple bind. | * PAM and Active Directory compliant authentication backends: Kerberos single sign-on, LDAP simple bind. | ||||||
| * POSIX groups and Active Directory (LDAP) group membership based authorization. | * POSIX groups and Active Directory (LDAP) group membership based authorization. | ||||||
| @@ -74,14 +74,14 @@ Common: | |||||||
| Virtual private networking: | Virtual private networking: | ||||||
|  |  | ||||||
| * Send VPN profile URL tokens via e-mail, for simplified VPN adoption on Android, iOS, Windows, Mac OS X and Ubuntu. | * Send VPN profile URL tokens via e-mail, for simplified VPN adoption on Android, iOS, Windows, Mac OS X and Ubuntu. | ||||||
| * OpenVPN gateway and roadwarrior integration, check out ``certidude setup openvpn server`` and ``certidude setup openvpn client``. | * OpenVPN gateway and roadwarrior integration, check out ``certidude provision openvpn server`` and ``certidude provision openvpn client``. | ||||||
| * StrongSwan gateway and roadwarrior integration, check out ``certidude setup strongswan server`` and ``certidude setup strongswan client``. | * StrongSwan gateway and roadwarrior integration, check out ``certidude provision strongswan server`` and ``certidude provision strongswan client``. | ||||||
| * NetworkManager integration for Ubuntu and Fedora, check out ``certidude setup openvpn networkmanager`` and ``certidude setup strongswan networkmanager``. | * NetworkManager integration for Ubuntu and Fedora, check out ``certidude provision openvpn networkmanager`` and ``certidude provision strongswan networkmanager``. | ||||||
|  |  | ||||||
| HTTPS: | HTTPS: | ||||||
|  |  | ||||||
| * P12 bundle generation for web browsers, seems to work well with Android | * P12 bundle generation for web browsers, seems to work well with Android | ||||||
| * HTTPS server setup with client verification, check out ``certidude setup nginx`` | * HTTPS server setup with client verification, check out ``certidude provision nginx`` | ||||||
|  |  | ||||||
|  |  | ||||||
| Install | Install | ||||||
| @@ -141,7 +141,7 @@ cronjobs in ``/etc/cron.hourly/certidude`` and much more: | |||||||
|  |  | ||||||
| .. code:: bash | .. code:: bash | ||||||
|  |  | ||||||
|     certidude setup authority |     certidude provision authority | ||||||
|  |  | ||||||
| Tweak the configuration in ``/etc/certidude/server.conf`` until you meet your requirements, | Tweak the configuration in ``/etc/certidude/server.conf`` until you meet your requirements, | ||||||
| to apply changes run: | to apply changes run: | ||||||
| @@ -170,7 +170,7 @@ Python modules: | |||||||
|  |  | ||||||
|     pip3 install simplepam |     pip3 install simplepam | ||||||
|  |  | ||||||
| The default configuration generated by ``certidude setup`` should make use of the | The default configuration generated by ``certidude provision`` should make use of the | ||||||
| PAM. | PAM. | ||||||
|  |  | ||||||
| Setting up Active Directory authentication | Setting up Active Directory authentication | ||||||
| @@ -335,6 +335,17 @@ To uninstall: | |||||||
|     pip3 uninstall certidude |     pip3 uninstall certidude | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Docker | ||||||
|  | ------ | ||||||
|  |  | ||||||
|  | .. code:: bash | ||||||
|  |  | ||||||
|  |     git clone https://github.com/laurivosandi/certidude | ||||||
|  |     cd certidude | ||||||
|  |     docker build . | ||||||
|  |     docker run --name ca --hostname ca.example.lan | ||||||
|  |  | ||||||
|  |  | ||||||
| Offline install | Offline install | ||||||
| --------------- | --------------- | ||||||
|  |  | ||||||
| @@ -367,6 +378,6 @@ Proceed to bootstrap authority without installing packages or assembling assets: | |||||||
|  |  | ||||||
| .. code:: bash | .. code:: bash | ||||||
|  |  | ||||||
|     certidude setup authority  --skip-packages --skip-assets [--elliptic-curve] [--organization "Mycorp LLC"] |     certidude provision authority  --skip-packages --skip-assets [--elliptic-curve] [--organization "Mycorp LLC"] | ||||||
|  |  | ||||||
| Note it's highly recommended to enable nginx PPA in the target machine | Note it's highly recommended to enable nginx PPA in the target machine | ||||||
|   | |||||||
| @@ -117,3 +117,6 @@ class OCSPResource(AuthorityHandler): | |||||||
|             } |             } | ||||||
|         }).dump() |         }).dump() | ||||||
|  |  | ||||||
|  |         # Interestingly openssl's OCSP code doesn't care about content type | ||||||
|  |         resp.append_header("Content-Type", "application/ocsp-response") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -43,6 +43,7 @@ def self_enroll(skip_notify=False): | |||||||
|  |  | ||||||
|     from certidude import const, config |     from certidude import const, config | ||||||
|     common_name = const.FQDN |     common_name = const.FQDN | ||||||
|  |     os.umask(0o0177) | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         path, buf, cert, signed, expires = get_signed(common_name) |         path, buf, cert, signed, expires = get_signed(common_name) | ||||||
|   | |||||||
| @@ -59,7 +59,7 @@ esac | |||||||
| cat << EOF > $OVERLAY/etc/certidude/authority/$AUTHORITY/updown | cat << EOF > $OVERLAY/etc/certidude/authority/$AUTHORITY/updown | ||||||
| #!/bin/sh | #!/bin/sh | ||||||
|  |  | ||||||
| CURL="curl -m 3 -f --key /etc/certidude/authority/$AUTHORITY/host_key.pem --cert /etc/certidude/authority/$AUTHORITY/host_cert.pem --cacert /etc/certidude/authority/$AUTHORITY/ca_cert.pem" | CURL="curl -m 3 -f --key /etc/certidude/authority/$AUTHORITY/host_key.pem --cert /etc/certidude/authority/$AUTHORITY/host_cert.pem --cacert /etc/certidude/authority/$AUTHORITY/ca_cert.pem --cert-status" | ||||||
| URL="https://$AUTHORITY:8443/api/signed/\$(uci get system.@system[0].hostname)/script/" | URL="https://$AUTHORITY:8443/api/signed/\$(uci get system.@system[0].hostname)/script/" | ||||||
|  |  | ||||||
| case \$PLUTO_VERB in | case \$PLUTO_VERB in | ||||||
|   | |||||||
| @@ -96,7 +96,7 @@ fi | |||||||
|  |  | ||||||
| logger -t certidude -s "Request md5sum is $(md5sum -b $REQUEST_PATH)" | logger -t certidude -s "Request md5sum is $(md5sum -b $REQUEST_PATH)" | ||||||
|  |  | ||||||
| curl -f -L \ | curl --cert-status -f -L \ | ||||||
|     -H "Content-Type: application/pkcs10" \ |     -H "Content-Type: application/pkcs10" \ | ||||||
|     --cacert $AUTHORITY_PATH \ |     --cacert $AUTHORITY_PATH \ | ||||||
|     --data-binary @$REQUEST_PATH \ |     --data-binary @$REQUEST_PATH \ | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ KEY_PATH=$DIR/host_key.pem | |||||||
|  |  | ||||||
| # TODO: fix Accepted 202 here | # TODO: fix Accepted 202 here | ||||||
|  |  | ||||||
| curl -f -L \ | curl --cert-status -f -L \ | ||||||
|     -H "Content-Type: application/pkcs10" \ |     -H "Content-Type: application/pkcs10" \ | ||||||
|     --data-binary @$REQUEST_PATH \ |     --data-binary @$REQUEST_PATH \ | ||||||
|     --cacert $AUTHORITY_PATH \ |     --cacert $AUTHORITY_PATH \ | ||||||
|   | |||||||
							
								
								
									
										213
									
								
								certidude/cli.py
									
									
									
									
									
								
							
							
						
						
									
										213
									
								
								certidude/cli.py
									
									
									
									
									
								
							| @@ -684,7 +684,7 @@ def certidude_enroll(fork, renew, no_wait, kerberos, skip_self): | |||||||
|     help="OpenVPN configuration file") |     help="OpenVPN configuration file") | ||||||
| @fqdn_required | @fqdn_required | ||||||
| @setup_client(prefix="server_", dh=True) | @setup_client(prefix="server_", dh=True) | ||||||
| def certidude_setup_openvpn_server(authority, common_name, config, subnet, route, local, proto, port, **paths): | def certidude_provision_openvpn_server(authority, common_name, config, subnet, route, local, proto, port, **paths): | ||||||
|     # Install dependencies |     # Install dependencies | ||||||
|     apt("openvpn") |     apt("openvpn") | ||||||
|     rpm("openvpn") |     rpm("openvpn") | ||||||
| @@ -745,7 +745,7 @@ def certidude_setup_openvpn_server(authority, common_name, config, subnet, route | |||||||
| @click.option("--verify-client", "-vc", default="optional", type=click.Choice(['optional', 'on', 'off'])) | @click.option("--verify-client", "-vc", default="optional", type=click.Choice(['optional', 'on', 'off'])) | ||||||
| @fqdn_required | @fqdn_required | ||||||
| @setup_client(prefix="server_", dh=True) | @setup_client(prefix="server_", dh=True) | ||||||
| def certidude_setup_nginx(authority, common_name, site_config, tls_config, verify_client, **paths): | def certidude_provision_nginx(authority, common_name, site_config, tls_config, verify_client, **paths): | ||||||
|  |  | ||||||
|     apt("nginx") |     apt("nginx") | ||||||
|     rpm("nginx") |     rpm("nginx") | ||||||
| @@ -759,16 +759,15 @@ def certidude_setup_nginx(authority, common_name, site_config, tls_config, verif | |||||||
|     if os.path.exists(site_config.name): |     if os.path.exists(site_config.name): | ||||||
|         click.echo("Configuration file %s already exists, not overwriting" % site_config.name) |         click.echo("Configuration file %s already exists, not overwriting" % site_config.name) | ||||||
|     else: |     else: | ||||||
|         site_config.write(env.get_template("nginx-https-site.conf").render(context)) |         site_config.write(env.get_template("snippets/nginx-https-site.conf").render(context)) | ||||||
|         click.echo("Generated %s" % site_config.name) |         click.echo("Generated %s" % site_config.name) | ||||||
|  |  | ||||||
|     if os.path.exists(tls_config.name): |     if os.path.exists(tls_config.name): | ||||||
|         click.echo("Configuration file %s already exists, not overwriting" % tls_config.name) |         click.echo("Configuration file %s already exists, not overwriting" % tls_config.name) | ||||||
|     else: |     else: | ||||||
|         tls_config.write(env.get_template("nginx-tls.conf").render(context)) |         tls_config.write(env.get_template("snippets/nginx-tls.conf").render(context)) | ||||||
|         click.echo("Generated %s" % tls_config.name) |         click.echo("Generated %s" % tls_config.name) | ||||||
|  |  | ||||||
|  |  | ||||||
|     click.echo() |     click.echo() | ||||||
|     click.echo("Inspect configuration files, enable it and start nginx service:") |     click.echo("Inspect configuration files, enable it and start nginx service:") | ||||||
|     click.echo() |     click.echo() | ||||||
| @@ -789,7 +788,7 @@ def certidude_setup_nginx(authority, common_name, site_config, tls_config, verif | |||||||
|     type=click.File(mode="w", atomic=True, lazy=True), |     type=click.File(mode="w", atomic=True, lazy=True), | ||||||
|     help="OpenVPN configuration file") |     help="OpenVPN configuration file") | ||||||
| @setup_client() | @setup_client() | ||||||
| def certidude_setup_openvpn_client(authority, remote, common_name, config, proto, **paths): | def certidude_provision_openvpn_client(authority, remote, common_name, config, proto, **paths): | ||||||
|     # Install dependencies |     # Install dependencies | ||||||
|     apt("openvpn") |     apt("openvpn") | ||||||
|     rpm("openvpn") |     rpm("openvpn") | ||||||
| @@ -843,7 +842,7 @@ def certidude_setup_openvpn_client(authority, remote, common_name, config, proto | |||||||
| @click.option("--route", "-r", type=ip_network, multiple=True, help="Subnets to advertise via this connection, multiple allowed") | @click.option("--route", "-r", type=ip_network, multiple=True, help="Subnets to advertise via this connection, multiple allowed") | ||||||
| @fqdn_required | @fqdn_required | ||||||
| @setup_client(prefix="server_") | @setup_client(prefix="server_") | ||||||
| def certidude_setup_strongswan_server(authority, common_name, subnet, route, **paths): | def certidude_provision_strongswan_server(authority, common_name, subnet, route, **paths): | ||||||
|     # Install dependencies |     # Install dependencies | ||||||
|     apt("strongswan") |     apt("strongswan") | ||||||
|     rpm("strongswan") |     rpm("strongswan") | ||||||
| @@ -892,7 +891,7 @@ def certidude_setup_strongswan_server(authority, common_name, subnet, route, **p | |||||||
| @click.argument("remote") | @click.argument("remote") | ||||||
| @click.option("--common-name", "-cn", default=const.HOSTNAME, help="Common name, %s by default" % const.HOSTNAME) | @click.option("--common-name", "-cn", default=const.HOSTNAME, help="Common name, %s by default" % const.HOSTNAME) | ||||||
| @setup_client() | @setup_client() | ||||||
| def certidude_setup_strongswan_client(authority, remote, common_name, **paths): | def certidude_provision_strongswan_client(authority, remote, common_name, **paths): | ||||||
|     # Install dependencies |     # Install dependencies | ||||||
|     apt("strongswan") or rpm("strongswan") |     apt("strongswan") or rpm("strongswan") | ||||||
|  |  | ||||||
| @@ -948,7 +947,7 @@ def certidude_setup_strongswan_client(authority, remote, common_name, **paths): | |||||||
| @click.argument("remote") # StrongSwan gateway | @click.argument("remote") # StrongSwan gateway | ||||||
| @click.option("--common-name", "-cn", default=const.HOSTNAME, help="Common name, %s by default" % const.HOSTNAME) | @click.option("--common-name", "-cn", default=const.HOSTNAME, help="Common name, %s by default" % const.HOSTNAME) | ||||||
| @setup_client() | @setup_client() | ||||||
| def certidude_setup_strongswan_networkmanager(authority, remote, common_name, **paths): | def certidude_provision_strongswan_networkmanager(authority, remote, common_name, **paths): | ||||||
|     # Install dependencies |     # Install dependencies | ||||||
|     apt("network-manager strongswan-nm") |     apt("network-manager strongswan-nm") | ||||||
|     rpm("NetworkManager NetworkManager-tui NetworkManager-strongswan-gnome") |     rpm("NetworkManager NetworkManager-tui NetworkManager-strongswan-gnome") | ||||||
| @@ -976,7 +975,7 @@ def certidude_setup_strongswan_networkmanager(authority, remote, common_name, ** | |||||||
| @click.argument("remote") # OpenVPN gateway | @click.argument("remote") # OpenVPN gateway | ||||||
| @click.option("--common-name", "-cn", default=const.HOSTNAME, help="Common name, %s by default" % const.HOSTNAME) | @click.option("--common-name", "-cn", default=const.HOSTNAME, help="Common name, %s by default" % const.HOSTNAME) | ||||||
| @setup_client() | @setup_client() | ||||||
| def certidude_setup_openvpn_networkmanager(authority, remote, common_name, **paths): | def certidude_provision_openvpn_networkmanager(authority, remote, common_name, **paths): | ||||||
|     apt("network-manager network-manager-openvpn-gnome") |     apt("network-manager network-manager-openvpn-gnome") | ||||||
|     rpm("NetworkManager NetworkManager-tui NetworkManager-openvpn-gnome") |     rpm("NetworkManager NetworkManager-tui NetworkManager-openvpn-gnome") | ||||||
|  |  | ||||||
| @@ -997,7 +996,7 @@ def certidude_setup_openvpn_networkmanager(authority, remote, common_name, **pat | |||||||
|         click.echo("Section %s added to /etc/certidude/client.conf" % endpoint) |         click.echo("Section %s added to /etc/certidude/client.conf" % endpoint) | ||||||
|  |  | ||||||
|  |  | ||||||
| @click.command("authority", help="Set up Certificate Authority in a directory") | @click.command("authority", help="Set up Certificate Authority") | ||||||
| @click.option("--username", default="certidude", help="Service user account, created if necessary, 'certidude' by default") | @click.option("--username", default="certidude", help="Service user account, created if necessary, 'certidude' by default") | ||||||
| @click.option("--kerberos-keytab", default="/etc/certidude/server.keytab", help="Kerberos keytab for using 'kerberos' authentication backend, /etc/certidude/server.keytab by default") | @click.option("--kerberos-keytab", default="/etc/certidude/server.keytab", help="Kerberos keytab for using 'kerberos' authentication backend, /etc/certidude/server.keytab by default") | ||||||
| @click.option("--nginx-config", "-n", | @click.option("--nginx-config", "-n", | ||||||
| @@ -1021,10 +1020,25 @@ def certidude_setup_openvpn_networkmanager(authority, remote, common_name, **pat | |||||||
| @click.option("--packages-only", is_flag=True, help="Install only apt/pip/npm packages") | @click.option("--packages-only", is_flag=True, help="Install only apt/pip/npm packages") | ||||||
| @click.option("--elliptic-curve", "-e", is_flag=True, help="Generate EC instead of RSA keypair") | @click.option("--elliptic-curve", "-e", is_flag=True, help="Generate EC instead of RSA keypair") | ||||||
| @click.option("--subordinate", is_flag=True, help="Set up subordinate CA instead of root CA") | @click.option("--subordinate", is_flag=True, help="Set up subordinate CA instead of root CA") | ||||||
| def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_config, organization, organizational_unit, common_name, directory, authority_lifetime, push_server, outbox, title, skip_assets, skip_packages, elliptic_curve, subordinate, packages_only): | def certidude_provision_authority(username, kerberos_keytab, nginx_config, tls_config, organization, organizational_unit, common_name, directory, authority_lifetime, push_server, outbox, title, skip_assets, skip_packages, elliptic_curve, subordinate, packages_only): | ||||||
|     assert subprocess.check_output(["/usr/bin/lsb_release", "-cs"]) in (b"trusty\n", b"xenial\n", b"bionic\n"), "Only Ubuntu 16.04 supported at the moment" |     assert subprocess.check_output(["/usr/bin/lsb_release", "-cs"]) in (b"trusty\n", b"xenial\n", b"bionic\n"), "Only Ubuntu 16.04 supported at the moment" | ||||||
|     assert os.getuid() == 0 and os.getgid() == 0, "Authority can be set up only by root" |     assert os.getuid() == 0 and os.getgid() == 0, "Authority can be set up only by root" | ||||||
|  |  | ||||||
|  |     def verbose_symlink(name, target): | ||||||
|  |         if not os.path.islink(name): | ||||||
|  |             click.echo("Symlinking %s to %s" % (name, target)) | ||||||
|  |             os.symlink(target, name) | ||||||
|  |         else: | ||||||
|  |             click.echo("Symlink %s already exist, remove to relink" % name) | ||||||
|  |  | ||||||
|  |     def verbose_makedirs(path): | ||||||
|  |         if not os.path.exists(path): | ||||||
|  |             click.echo("Creating directory %s" % path) | ||||||
|  |             os.makedirs(path) | ||||||
|  |         else: | ||||||
|  |             click.echo("Directory %s already exists" % path) | ||||||
|  |  | ||||||
|  |  | ||||||
|     import pwd |     import pwd | ||||||
|     from jinja2 import Environment, PackageLoader |     from jinja2 import Environment, PackageLoader | ||||||
|     env = Environment(loader=PackageLoader("certidude", "templates"), trim_blocks=True) |     env = Environment(loader=PackageLoader("certidude", "templates"), trim_blocks=True) | ||||||
| @@ -1070,8 +1084,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|         if os.system(cmd): |         if os.system(cmd): | ||||||
|             raise click.ClickException("Failed to install JavaScript packages") |             raise click.ClickException("Failed to install JavaScript packages") | ||||||
|  |  | ||||||
|     if not os.path.exists("/usr/bin/node"): |     verbose_symlink("/usr/bin/node", "/usr/bin/nodejs") | ||||||
|         os.symlink("/usr/bin/nodejs", "/usr/bin/node") |  | ||||||
|  |  | ||||||
|     if packages_only: |     if packages_only: | ||||||
|         return |         return | ||||||
| @@ -1100,7 +1113,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|     assets_dir = os.path.join(directory, "assets") |     assets_dir = os.path.join(directory, "assets") | ||||||
|     ca_key = os.path.join(directory, "ca_key.pem") |     ca_key = os.path.join(directory, "ca_key.pem") | ||||||
|     ca_req = os.path.join(directory, "ca_req.pem") |     ca_req = os.path.join(directory, "ca_req.pem") | ||||||
|     ca_cert = os.path.join(directory, "ca_cert.pem") |     authority_path = os.path.join(directory, "ca_cert.pem") | ||||||
|     self_key = os.path.join(directory, "self_key.pem") |     self_key = os.path.join(directory, "self_key.pem") | ||||||
|     sqlite_path = os.path.join(directory, "meta", "db.sqlite") |     sqlite_path = os.path.join(directory, "meta", "db.sqlite") | ||||||
|     distinguished_name = cn_to_dn(title, common_name, o=organization, ou=organizational_unit) |     distinguished_name = cn_to_dn(title, common_name, o=organization, ou=organizational_unit) | ||||||
| @@ -1120,7 +1133,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|     if os.path.exists(kerberos_keytab): |     if os.path.exists(kerberos_keytab): | ||||||
|         click.echo("Service principal keytab found in '%s'" % kerberos_keytab) |         click.echo("Service principal keytab found in '%s'" % kerberos_keytab) | ||||||
|     else: |     else: | ||||||
|         click.echo("To use 'kerberos' authentication backend join the domain , create service principal and provision authority again:") |         click.echo("To use 'kerberos' authentication backend join the domain, create service principal and provision authority again:") | ||||||
|         click.echo() |         click.echo() | ||||||
|         click.echo("  kinit administrator@EXAMPLE.LAN") |         click.echo("  kinit administrator@EXAMPLE.LAN") | ||||||
|         click.echo("  net ads join -k") |         click.echo("  net ads join -k") | ||||||
| @@ -1128,17 +1141,9 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|         click.echo("  kdestroy") |         click.echo("  kdestroy") | ||||||
|         click.echo("  chown %s %s" % (username, kerberos_keytab)) |         click.echo("  chown %s %s" % (username, kerberos_keytab)) | ||||||
|         click.echo("  mv /etc/certidude/server.conf /etc/certidude/server.backup") |         click.echo("  mv /etc/certidude/server.conf /etc/certidude/server.backup") | ||||||
|         click.echo("  certidude setup authority") |         click.echo("  certidude provision authority") | ||||||
|         click.echo() |         click.echo() | ||||||
|  |  | ||||||
|  |  | ||||||
|     for interval in ("hourly", "daily"): |  | ||||||
|         if not os.path.exists("/etc/cron.%s/certidude" % interval): |  | ||||||
|             with open("/etc/cron.%s/certidude" % interval, "w") as fh: |  | ||||||
|                 fh.write("#!/bin/bash\nLANG=C.UTF-8 certidude cron %s\n" % interval) |  | ||||||
|             os.chmod("/etc/cron.%s/certidude" % interval, 0o755) |  | ||||||
|             click.echo("Created /etc/cron.%s/certidude" % interval) |  | ||||||
|  |  | ||||||
|     if os.path.exists("/etc/krb5.keytab") and os.path.exists("/etc/samba/smb.conf"): |     if os.path.exists("/etc/krb5.keytab") and os.path.exists("/etc/samba/smb.conf"): | ||||||
|         # Fetch Kerberos ticket for system account |         # Fetch Kerberos ticket for system account | ||||||
|         cp = ConfigParser() |         cp = ConfigParser() | ||||||
| @@ -1148,6 +1153,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|         name = cp.get("global", "netbios name") |         name = cp.get("global", "netbios name") | ||||||
|         base = ",".join(["dc=" + j for j in domain.split(".")]) |         base = ",".join(["dc=" + j for j in domain.split(".")]) | ||||||
|     else: |     else: | ||||||
|  |         realm = None | ||||||
|         click.echo("Warning: /etc/krb5.keytab or /etc/samba/smb.conf not found, Kerberos unconfigured") |         click.echo("Warning: /etc/krb5.keytab or /etc/samba/smb.conf not found, Kerberos unconfigured") | ||||||
|  |  | ||||||
|     letsencrypt_fullchain = "/etc/letsencrypt/live/%s/fullchain.pem" % common_name |     letsencrypt_fullchain = "/etc/letsencrypt/live/%s/fullchain.pem" % common_name | ||||||
| @@ -1157,25 +1163,35 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|     builder_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), "builder") |     builder_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), "builder") | ||||||
|     script_dir = os.path.join(os.path.realpath(os.path.dirname(__file__)), "templates", "script") |     script_dir = os.path.join(os.path.realpath(os.path.dirname(__file__)), "templates", "script") | ||||||
|  |  | ||||||
|  |     templates_dir = os.path.join(os.path.realpath(os.path.dirname(__file__)), "templates") | ||||||
|     static_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), "static") |     static_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), "static") | ||||||
|     certidude_path = sys.argv[0] |     certidude_path = sys.argv[0] | ||||||
|  |  | ||||||
|     click.echo("Generating: %s" % nginx_config.name) |     click.echo("Generating: %s" % nginx_config.name) | ||||||
|     nginx_config.write(env.get_template("server/nginx.conf").render(vars())) |     nginx_config.write(env.get_template("server/nginx.conf").render(vars())) | ||||||
|     nginx_config.close() |     nginx_config.close() | ||||||
|     if not os.path.exists("/etc/nginx/sites-enabled/certidude.conf"): |  | ||||||
|         os.symlink("../sites-available/certidude.conf", "/etc/nginx/sites-enabled/certidude.conf") |     def verbose_render_systemd_service(template, target, context): | ||||||
|         click.echo("Symlinked %s -> /etc/nginx/sites-enabled/" % nginx_config.name) |         target_path = "/etc/systemd/system/%s" % target | ||||||
|  |         if os.path.exists(target_path): | ||||||
|  |             click.echo("File %s already exists, remove to regenerate" % target_path) | ||||||
|  |         else: | ||||||
|  |             buf = env.get_template(template).render(context) | ||||||
|  |             with open(target_path, "w") as fh: | ||||||
|  |                 fh.write(buf) | ||||||
|  |             click.echo("File %s created" % target_path) | ||||||
|  |             os.system("systemctl daemon-reload") | ||||||
|  |  | ||||||
|  |     verbose_symlink("/etc/nginx/sites-enabled/certidude.conf", "../sites-available/certidude.conf") | ||||||
|  |  | ||||||
|     if os.path.exists("/etc/nginx/sites-enabled/default"): |     if os.path.exists("/etc/nginx/sites-enabled/default"): | ||||||
|         os.unlink("/etc/nginx/sites-enabled/default") |         os.unlink("/etc/nginx/sites-enabled/default") | ||||||
|     if os.path.exists("/etc/systemd"): |     if os.path.exists("/etc/systemd"): | ||||||
|         if os.path.exists("/etc/systemd/system/certidude.service"): |         verbose_render_systemd_service("server/backend.service", "certidude-backend.service", vars()) | ||||||
|             click.echo("File /etc/systemd/system/certidude.service already exists, remove to regenerate") |         verbose_render_systemd_service("server/ldap-kinit.service", "certidude-ldap-kinit.service", vars()) | ||||||
|         else: |         verbose_render_systemd_service("server/ldap-kinit.timer", "certidude-ldap-kinit.timer", vars()) | ||||||
|             with open("/etc/systemd/system/certidude.service", "w") as fh: |         verbose_render_systemd_service("snippets/nginx-ocsp-cache.service", "certidude-ocsp-cache.service", vars()) | ||||||
|                 fh.write(env.get_template("server/systemd.service").render(vars())) |         verbose_render_systemd_service("snippets/nginx-ocsp-cache.timer", "certidude-ocsp-cache.timer", vars()) | ||||||
|             click.echo("File /etc/systemd/system/certidude.service created") |  | ||||||
|             os.system("systemctl daemon-reload") |  | ||||||
|     else: |     else: | ||||||
|         raise NotImplementedError("Not systemd based OS, don't know how to set up initscripts") |         raise NotImplementedError("Not systemd based OS, don't know how to set up initscripts") | ||||||
|  |  | ||||||
| @@ -1209,7 +1225,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|                 raise click.ClickException("Failed to copy fonts") |                 raise click.ClickException("Failed to copy fonts") | ||||||
|  |  | ||||||
|             # Compile nunjucks templates |             # Compile nunjucks templates | ||||||
|             cmd = 'nunjucks-precompile --include "\.html$" --include "\.ps1$" --include "\.sh$" --include "\.svg$" --include "\.yml$" --include "\.conf$" --include "\.mobileconfig$" %s > %s.part' % (static_path, bundle_js) |             cmd = 'nunjucks-precompile --include snippets --include views %s > %s.part' % (templates_dir, bundle_js) | ||||||
|             click.echo("Compiling templates: %s" % cmd) |             click.echo("Compiling templates: %s" % cmd) | ||||||
|             if os.system(cmd): |             if os.system(cmd): | ||||||
|                 raise click.ClickException("Failed to compile nunjucks templates") |                 raise click.ClickException("Failed to compile nunjucks templates") | ||||||
| @@ -1256,7 +1272,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|         if os.path.exists(tls_config.name): |         if os.path.exists(tls_config.name): | ||||||
|             click.echo("Configuration file %s already exists, not overwriting" % tls_config.name) |             click.echo("Configuration file %s already exists, not overwriting" % tls_config.name) | ||||||
|         else: |         else: | ||||||
|             tls_config.write(env.get_template("nginx-tls.conf").render(locals())) |             tls_config.write(env.get_template("snippets/nginx-tls.conf").render(locals())) | ||||||
|             click.echo("Generated %s" % tls_config.name) |             click.echo("Generated %s" % tls_config.name) | ||||||
|  |  | ||||||
|         if os.path.exists(const.SERVER_CONFIG_PATH): |         if os.path.exists(const.SERVER_CONFIG_PATH): | ||||||
| @@ -1295,11 +1311,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|         os.umask(0o007) |         os.umask(0o007) | ||||||
|         for subdir in ("signed", "signed/by-serial", "requests", "revoked", "expired", "meta", "builder"): |         for subdir in ("signed", "signed/by-serial", "requests", "revoked", "expired", "meta", "builder"): | ||||||
|             path = os.path.join(directory, subdir) |             path = os.path.join(directory, subdir) | ||||||
|             if not os.path.exists(path): |             verbose_makedirs(path) | ||||||
|                 click.echo("Creating directory %s" % path) |  | ||||||
|                 os.mkdir(path) |  | ||||||
|             else: |  | ||||||
|                 click.echo("Directory already exists %s" % path) |  | ||||||
|             assert os.stat(path).st_mode == 0o40770, path |             assert os.stat(path).st_mode == 0o40770, path | ||||||
|  |  | ||||||
|         # Create SQLite database file with correct permissions |         # Create SQLite database file with correct permissions | ||||||
| @@ -1308,6 +1320,21 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|             with open(sqlite_path, "wb") as fh: |             with open(sqlite_path, "wb") as fh: | ||||||
|                 pass |                 pass | ||||||
|  |  | ||||||
|  |         # Create symlink for self certificate | ||||||
|  |         verbose_symlink("/var/lib/certidude/self_cert.pem", "signed/" + common_name + ".pem") | ||||||
|  |  | ||||||
|  |         # Symlink client paths | ||||||
|  |         verbose_makedirs("/etc/certidude/authority/%s" % common_name) | ||||||
|  |         verbose_symlink( | ||||||
|  |             "/etc/certidude/authority/%s/host_cert.pem" % common_name, | ||||||
|  |             "/var/lib/certidude/self_cert.pem") | ||||||
|  |         verbose_symlink( | ||||||
|  |             "/etc/certidude/authority/%s/host_key.pem" % common_name, | ||||||
|  |             "/var/lib/certidude/self_key.pem") | ||||||
|  |         verbose_symlink( | ||||||
|  |             "/etc/certidude/authority/%s/ca_cert.pem" % common_name, | ||||||
|  |             "/var/lib/certidude/ca_cert.pem") | ||||||
|  |  | ||||||
|         # Generate and sign CA key |         # Generate and sign CA key | ||||||
|         if not os.path.exists(ca_key) or subordinate and not os.path.exists(ca_req): |         if not os.path.exists(ca_key) or subordinate and not os.path.exists(ca_req): | ||||||
|             if elliptic_curve: |             if elliptic_curve: | ||||||
| @@ -1329,22 +1356,22 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|                     f.write(pem_armor_csr(request)) |                     f.write(pem_armor_csr(request)) | ||||||
|                 os.rename(ca_req + ".part", ca_req) |                 os.rename(ca_req + ".part", ca_req) | ||||||
|  |  | ||||||
|         if not os.path.exists(ca_cert): |         if not os.path.exists(authority_path): | ||||||
|             if subordinate: |             if subordinate: | ||||||
|                 click.echo("Request has been written to %s" % ca_req) |                 click.echo("Request has been written to %s" % ca_req) | ||||||
|                 click.echo() |                 click.echo() | ||||||
|                 click.echo(open(ca_req).read()) |                 click.echo(open(ca_req).read()) | ||||||
|                 click.echo() |                 click.echo() | ||||||
|                 click.echo("Get it signed and insert signed certificate into %s" % ca_cert) |                 click.echo("Get it signed and insert signed certificate into %s" % authority_path) | ||||||
|                 click.echo() |                 click.echo() | ||||||
|                 click.echo("  cat > %s" % ca_cert) |                 click.echo("  cat > %s" % authority_path) | ||||||
|                 click.echo() |                 click.echo() | ||||||
|                 click.echo("Paste contents and press Ctrl-D, adjust permissions:") |                 click.echo("Paste contents and press Ctrl-D, adjust permissions:") | ||||||
|                 click.echo() |                 click.echo() | ||||||
|                 click.echo("  chown root:root %s" % ca_cert) |                 click.echo("  chown root:root %s" % authority_path) | ||||||
|                 click.echo("  chmod 0644 %s" % ca_cert) |                 click.echo("  chmod 0644 %s" % authority_path) | ||||||
|                 click.echo() |                 click.echo() | ||||||
|                 click.echo("To finish setup procedure run 'certidude setup authority' again") |                 click.echo("To finish setup procedure run 'certidude provision authority' again") | ||||||
|                 sys.exit(1) # stop this fork here with error |                 sys.exit(1) # stop this fork here with error | ||||||
|  |  | ||||||
|             # https://technet.microsoft.com/en-us/library/aa998840(v=exchg.141).aspx |             # https://technet.microsoft.com/en-us/library/aa998840(v=exchg.141).aspx | ||||||
| @@ -1360,9 +1387,9 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|  |  | ||||||
|             # Set permission bits to 640 |             # Set permission bits to 640 | ||||||
|             os.umask(0o137) |             os.umask(0o137) | ||||||
|             with open(ca_cert, 'wb') as f: |             with open(authority_path, 'wb') as f: | ||||||
|                 f.write(pem_armor_certificate(certificate)) |                 f.write(pem_armor_certificate(certificate)) | ||||||
|             click.echo("Authority certificate written to: %s" % ca_cert) |             click.echo("Authority certificate written to: %s" % authority_path) | ||||||
|  |  | ||||||
|         sys.exit(0) # stop this fork here |         sys.exit(0) # stop this fork here | ||||||
|     else: |     else: | ||||||
| @@ -1376,18 +1403,27 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|         assert os.path.exists(os.path.join(directory, "signed", common_name) + ".pem") |         assert os.path.exists(os.path.join(directory, "signed", common_name) + ".pem") | ||||||
|         assert os.getuid() == 0 and os.getgid() == 0, "Enroll contaminated environment" |         assert os.getuid() == 0 and os.getgid() == 0, "Enroll contaminated environment" | ||||||
|         assert os.stat(sqlite_path).st_mode == 0o100660 |         assert os.stat(sqlite_path).st_mode == 0o100660 | ||||||
|         assert os.stat(ca_cert).st_mode == 0o100640 |         assert os.stat(authority_path).st_mode == 0o100640 | ||||||
|         assert os.stat(ca_key).st_mode == 0o100600 |         assert os.stat(ca_key).st_mode == 0o100600 | ||||||
|  |         assert os.stat(self_key).st_mode == 0o100600 | ||||||
|         assert os.stat("/etc/nginx/sites-available/certidude.conf").st_mode == 0o100600 |         assert os.stat("/etc/nginx/sites-available/certidude.conf").st_mode == 0o100600 | ||||||
|         assert os.stat("/etc/certidude/server.conf").st_mode == 0o100600 |         assert os.stat("/etc/certidude/server.conf").st_mode == 0o100600 | ||||||
|  |  | ||||||
|  |         # Disable legacy garbage | ||||||
|  |         if os.path.exists("/etc/cron.hourly/certidude"): | ||||||
|  |             os.unlink("/etc/cron.hourly/certidude") | ||||||
|  |         if os.path.exists("/etc/cron.daily/certidude"): | ||||||
|  |             os.unlink("/etc/cron.daily/certidude") | ||||||
|  |         if os.path.exists("/etc/systemd/system/certidude.service"): | ||||||
|  |             os.unlink("/etc/systemd/system/certidude.service") | ||||||
|  |  | ||||||
|         click.echo("To enable e-mail notifications install Postfix as sattelite system and set mailer address in %s" % const.SERVER_CONFIG_PATH) |         click.echo("To enable e-mail notifications install Postfix as sattelite system and set mailer address in %s" % const.SERVER_CONFIG_PATH) | ||||||
|         click.echo() |         click.echo() | ||||||
|         click.echo("Use following commands to inspect the newly created files:") |         click.echo("Use following commands to inspect the newly created files:") | ||||||
|         click.echo() |         click.echo() | ||||||
|         click.echo("  openssl x509 -text -noout -in %s | less" % ca_cert) |         click.echo("  openssl x509 -text -noout -in %s | less" % authority_path) | ||||||
|         click.echo("  openssl rsa -check -in %s" % ca_key) |         click.echo("  openssl rsa -check -in %s" % ca_key) | ||||||
|         click.echo("  openssl verify -CAfile %s %s" % (ca_cert, ca_cert)) |         click.echo("  openssl verify -CAfile %s %s" % (authority_path, authority_path)) | ||||||
|         click.echo() |         click.echo() | ||||||
|         click.echo("To inspect logs and issued tokens:") |         click.echo("To inspect logs and issued tokens:") | ||||||
|         click.echo() |         click.echo() | ||||||
| @@ -1395,12 +1431,19 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi | |||||||
|         click.echo("  echo 'select * from token;' | sqlite3 /var/lib/certidude/meta/db.sqlite") |         click.echo("  echo 'select * from token;' | sqlite3 /var/lib/certidude/meta/db.sqlite") | ||||||
|         click.echo() |         click.echo() | ||||||
|         click.echo("Enabling Certidude backend and nginx...") |         click.echo("Enabling Certidude backend and nginx...") | ||||||
|         os.system("systemctl enable certidude") |         os.system("systemctl enable certidude-backend.service") | ||||||
|         os.system("systemctl enable nginx") |         os.system("systemctl enable nginx") | ||||||
|  |         os.system("systemctl enable certidude-ocsp-cache.timer") | ||||||
|  |         os.system("systemctl start certidude-ocsp-cache.timer") | ||||||
|  |         if realm: | ||||||
|  |             os.system("systemctl enable certidude-ldap-kinit.timer") | ||||||
|  |             os.system("systemctl start certidude-ldap-kinit.timer") | ||||||
|  |             os.system("systemctl start certidude-ldap-kinit.service") | ||||||
|         click.echo("To (re)start services:") |         click.echo("To (re)start services:") | ||||||
|         click.echo() |         click.echo() | ||||||
|         click.echo("  systemctl restart certidude") |         click.echo("  systemctl restart certidude-backend") | ||||||
|         click.echo("  systemctl restart nginx") |         click.echo("  systemctl restart nginx") | ||||||
|  |         click.echo("  systemctl start certidude-ocsp-cache.service") | ||||||
|         click.echo() |         click.echo() | ||||||
|         return 0 |         return 0 | ||||||
|  |  | ||||||
| @@ -1517,8 +1560,8 @@ def certidude_revoke(common_name, reason): | |||||||
|     authority.revoke(common_name, reason) |     authority.revoke(common_name, reason) | ||||||
|  |  | ||||||
|  |  | ||||||
| @click.command("hourly", help="Hourly housekeeping tasks") | @click.command("kinit", help="Initialize Kerberos credential cache for LDAP") | ||||||
| def certidude_cron_hourly(): | def certidude_housekeeping_kinit(): | ||||||
|     from certidude import config |     from certidude import config | ||||||
|  |  | ||||||
|     # Update LDAP service ticket if Certidude is joined to domain |     # Update LDAP service ticket if Certidude is joined to domain | ||||||
| @@ -1535,8 +1578,8 @@ def certidude_cron_hourly(): | |||||||
|         os.rename("/run/certidude/krb5cc.part", "/run/certidude/krb5cc") |         os.rename("/run/certidude/krb5cc.part", "/run/certidude/krb5cc") | ||||||
|  |  | ||||||
|  |  | ||||||
| @click.command("daily", help="Daily housekeeping tasks") | @click.command("daily", help="Send notifications about expired certificates") | ||||||
| def certidude_cron_daily(): | def certidude_housekeeping_expiration(): | ||||||
|     from certidude import authority, config, mailer |     from certidude import authority, config, mailer | ||||||
|     threshold_move = datetime.utcnow() - const.CLOCK_SKEW_TOLERANCE |     threshold_move = datetime.utcnow() - const.CLOCK_SKEW_TOLERANCE | ||||||
|     threshold_notify = datetime.utcnow() + timedelta(hours=48) |     threshold_notify = datetime.utcnow() + timedelta(hours=48) | ||||||
| @@ -1633,11 +1676,6 @@ def certidude_serve(port, listen, fork): | |||||||
|     Drop privileges |     Drop privileges | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|  |  | ||||||
|     # Initialize LDAP service ticket |  | ||||||
|     if os.path.exists("/etc/cron.hourly/certidude"): |  | ||||||
|         os.system("/etc/cron.hourly/certidude") |  | ||||||
|  |  | ||||||
|     from certidude.push import EventSourceLogHandler |     from certidude.push import EventSourceLogHandler | ||||||
|     log_handlers.append(EventSourceLogHandler()) |     log_handlers.append(EventSourceLogHandler()) | ||||||
|  |  | ||||||
| @@ -1671,7 +1709,7 @@ def certidude_serve(port, listen, fork): | |||||||
| @click.option("-p", "--pin", default="123456", help="Slot pincode, 123456 by default") | @click.option("-p", "--pin", default="123456", help="Slot pincode, 123456 by default") | ||||||
| @click.option("-s", "--slot", default="9a", help="Yubikey slot to use, 9a by default") | @click.option("-s", "--slot", default="9a", help="Yubikey slot to use, 9a by default") | ||||||
| @click.option("-u", "--username", default=os.getenv("USER"), help="Username to use, %s by default" % os.getenv("USER")) | @click.option("-u", "--username", default=os.getenv("USER"), help="Username to use, %s by default" % os.getenv("USER")) | ||||||
| def certidude_setup_yubikey(authority, slot, username, pin): | def certidude_provision_yubikey(authority, slot, username, pin): | ||||||
|     import requests |     import requests | ||||||
|     cmd = "ykinfo", "-q", "-s" |     cmd = "ykinfo", "-q", "-s" | ||||||
|     click.echo("Executing: %s" % " ".join(cmd)) |     click.echo("Executing: %s" % " ".join(cmd)) | ||||||
| @@ -1750,47 +1788,48 @@ def certidude_token_issue(subject, subject_mail): | |||||||
|  |  | ||||||
|  |  | ||||||
| @click.group("strongswan", help="strongSwan helpers") | @click.group("strongswan", help="strongSwan helpers") | ||||||
| def certidude_setup_strongswan(): pass | def certidude_provision_strongswan(): pass | ||||||
|  |  | ||||||
| @click.group("openvpn", help="OpenVPN helpers") | @click.group("openvpn", help="OpenVPN helpers") | ||||||
| def certidude_setup_openvpn(): pass | def certidude_provision_openvpn(): pass | ||||||
|  |  | ||||||
| @click.group("setup", help="Getting started section") | @click.group("provision", help="Getting started section") | ||||||
| def certidude_setup(): pass | def certidude_provision(): pass | ||||||
|  |  | ||||||
|  | @click.group("housekeeping", help="Housekeeping tasks") | ||||||
|  | def certidude_housekeeping(): pass | ||||||
|  |  | ||||||
| @click.group("token", help="Token management") | @click.group("token", help="Token management") | ||||||
| def certidude_token(): pass | def certidude_token(): pass | ||||||
|  |  | ||||||
| @click.group("cron", help="Housekeeping tasks") |  | ||||||
| def certidude_cron(): pass |  | ||||||
|  |  | ||||||
| @click.group() | @click.group() | ||||||
| def entry_point(): pass | def entry_point(): pass | ||||||
|  |  | ||||||
| certidude_setup_strongswan.add_command(certidude_setup_strongswan_server) |  | ||||||
| certidude_setup_strongswan.add_command(certidude_setup_strongswan_client) | certidude_provision_strongswan.add_command(certidude_provision_strongswan_server) | ||||||
| certidude_setup_strongswan.add_command(certidude_setup_strongswan_networkmanager) | certidude_provision_strongswan.add_command(certidude_provision_strongswan_client) | ||||||
| certidude_setup_openvpn.add_command(certidude_setup_openvpn_server) | certidude_provision_strongswan.add_command(certidude_provision_strongswan_networkmanager) | ||||||
| certidude_setup_openvpn.add_command(certidude_setup_openvpn_client) | certidude_provision_openvpn.add_command(certidude_provision_openvpn_server) | ||||||
| certidude_setup_openvpn.add_command(certidude_setup_openvpn_networkmanager) | certidude_provision_openvpn.add_command(certidude_provision_openvpn_client) | ||||||
| certidude_setup.add_command(certidude_setup_authority) | certidude_provision_openvpn.add_command(certidude_provision_openvpn_networkmanager) | ||||||
| certidude_setup.add_command(certidude_setup_openvpn) | certidude_provision.add_command(certidude_provision_authority) | ||||||
| certidude_setup.add_command(certidude_setup_strongswan) | certidude_provision.add_command(certidude_provision_openvpn) | ||||||
| certidude_setup.add_command(certidude_setup_nginx) | certidude_provision.add_command(certidude_provision_strongswan) | ||||||
| certidude_setup.add_command(certidude_setup_yubikey) | certidude_provision.add_command(certidude_provision_nginx) | ||||||
|  | certidude_provision.add_command(certidude_provision_yubikey) | ||||||
| certidude_token.add_command(certidude_token_list) | certidude_token.add_command(certidude_token_list) | ||||||
| certidude_token.add_command(certidude_token_purge) | certidude_token.add_command(certidude_token_purge) | ||||||
| certidude_token.add_command(certidude_token_issue) | certidude_token.add_command(certidude_token_issue) | ||||||
| certidude_cron.add_command(certidude_cron_hourly) | certidude_housekeeping.add_command(certidude_housekeeping_kinit) | ||||||
| certidude_cron.add_command(certidude_cron_daily) | certidude_housekeeping.add_command(certidude_housekeeping_expiration) | ||||||
| entry_point.add_command(certidude_token) | entry_point.add_command(certidude_token) | ||||||
| entry_point.add_command(certidude_setup) | entry_point.add_command(certidude_provision) | ||||||
| entry_point.add_command(certidude_serve) | entry_point.add_command(certidude_serve) | ||||||
| entry_point.add_command(certidude_enroll) | entry_point.add_command(certidude_enroll) | ||||||
| entry_point.add_command(certidude_sign) | entry_point.add_command(certidude_sign) | ||||||
| entry_point.add_command(certidude_revoke) | entry_point.add_command(certidude_revoke) | ||||||
| entry_point.add_command(certidude_list) | entry_point.add_command(certidude_list) | ||||||
| entry_point.add_command(certidude_cron) | entry_point.add_command(certidude_housekeeping) | ||||||
| entry_point.add_command(certidude_users) | entry_point.add_command(certidude_users) | ||||||
| entry_point.add_command(certidude_test) | entry_point.add_command(certidude_test) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -546,7 +546,15 @@ function loadAuthority(query) { | |||||||
|              **/ |              **/ | ||||||
|             $("#view-dashboard").html(env.render('views/authority.html', { |             $("#view-dashboard").html(env.render('views/authority.html', { | ||||||
|                 session: session, |                 session: session, | ||||||
|                 window: window |                 window: window, | ||||||
|  |  | ||||||
|  |                 // Parameters for unified snippets | ||||||
|  |                 dhparam_path: "/etc/ssl/dhparam.pem", | ||||||
|  |                 key_path: "/etc/certidude/authority/" + session.authority.hostname + "/host_key.pem", | ||||||
|  |                 certificate_path: "/etc/certidude/authority/" + session.authority.hostname + "/host_cert.pem", | ||||||
|  |                 authority_path: "/etc/certidude/authority/" + session.authority.hostname + "/ca_cert.pem", | ||||||
|  |                 revocations_path: "/etc/certidude/authority/" + session.authority.hostname + "/crl.pem", | ||||||
|  |                 common_name: "$NAME" | ||||||
|             })); |             })); | ||||||
|  |  | ||||||
|             $("time").timeago(); |             $("time").timeago(); | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ else | |||||||
| fi | fi | ||||||
|  |  | ||||||
| # Submit some stats to CA | # Submit some stats to CA | ||||||
| curl https://{{ authority_name }}:8443/api/signed/{{ common_name }}/attr \ | curl --cert-status https://{{ authority_name }}:8443/api/signed/{{ common_name }}/attr \ | ||||||
| --cacert /etc/certidude/authority/{{ authority_name }}/ca_cert.pem \ | --cacert /etc/certidude/authority/{{ authority_name }}/ca_cert.pem \ | ||||||
| --key /etc/certidude/authority/{{ authority_name }}/host_key.pem \ | --key /etc/certidude/authority/{{ authority_name }}/host_key.pem \ | ||||||
| --cert /etc/certidude/authority/{{ authority_name }}/host_cert.pem \ | --cert /etc/certidude/authority/{{ authority_name }}/host_cert.pem \ | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								certidude/templates/server/backend.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								certidude/templates/server/backend.service
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | [Unit] | ||||||
|  | Description=Certidude server | ||||||
|  | After=network.target | ||||||
|  |  | ||||||
|  | [Service] | ||||||
|  | Type=forking | ||||||
|  | EnvironmentFile=/etc/environment | ||||||
|  | Environment=LANG=C.UTF-8 | ||||||
|  | Environment=PYTHON_EGG_CACHE=/tmp/.cache | ||||||
|  | PIDFile=/run/certidude/server.pid | ||||||
|  | KillSignal=SIGINT | ||||||
|  | ExecStart={{ certidude_path }} serve --fork | ||||||
|  | TimeoutSec=15 | ||||||
|  |  | ||||||
|  | [Install] | ||||||
|  | WantedBy=multi-user.target | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								certidude/templates/server/ldap-kinit.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								certidude/templates/server/ldap-kinit.service
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | [Unit] | ||||||
|  | Description=Initialize Kerberos credential cache for LDAP connections of Certidude | ||||||
|  |  | ||||||
|  | [Service] | ||||||
|  | Type=oneshot | ||||||
|  | ExecStart={{ certidude_path }} housekeeping kinit | ||||||
|  | Before=certidude-backend.service | ||||||
							
								
								
									
										3
									
								
								certidude/templates/server/ldap-kinit.timer
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								certidude/templates/server/ldap-kinit.timer
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | [Timer] | ||||||
|  | OnCalendar=00/8:30 | ||||||
|  | Persistent=true | ||||||
| @@ -137,10 +137,16 @@ server { | |||||||
|     server_name {{ common_name }}; |     server_name {{ common_name }}; | ||||||
|     listen 8443 ssl http2; |     listen 8443 ssl http2; | ||||||
|  |  | ||||||
|  |     # Enforce OCSP stapling for the server certificate | ||||||
|  |     # Note that even nginx 1.14.0 doesn't immideately populate the OCSP cache | ||||||
|  |     # You need to run separate cronjob to populate the OCSP response cache | ||||||
|  |     ssl_stapling on; | ||||||
|  |     ssl_stapling_verify on; | ||||||
|  |  | ||||||
|     # Allow client authentication with certificate, |     # Allow client authentication with certificate, | ||||||
|     # backend must still check if certificate was used for TLS handshake |     # backend must still check if certificate was used for TLS handshake | ||||||
|     ssl_verify_client optional; |     ssl_verify_client optional; | ||||||
|     ssl_client_certificate {{ directory }}/ca_cert.pem; |     ssl_client_certificate {{ authority_path }}; | ||||||
|  |  | ||||||
|     # Proxy pass to backend |     # Proxy pass to backend | ||||||
|     location /api/ { |     location /api/ { | ||||||
|   | |||||||
| @@ -218,7 +218,7 @@ user enrollment = multiple allowed | |||||||
|  |  | ||||||
| # Certificate authority keypair | # Certificate authority keypair | ||||||
| private key path = {{ ca_key }} | private key path = {{ ca_key }} | ||||||
| certificate path = {{ ca_cert }} | certificate path = {{ authority_path }} | ||||||
|  |  | ||||||
| # Private key used by nginx frontend | # Private key used by nginx frontend | ||||||
| self key path = {{ self_key }} | self key path = {{ self_key }} | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| cat <<\EOF > /etc/certidude/authority/{{ session.authority.hostname }}/updown | cat <<\EOF > /etc/certidude/authority/{{ session.authority.hostname }}/updown | ||||||
| #!/bin/sh | #!/bin/sh | ||||||
| 
 | 
 | ||||||
| CURL="curl -m 3 -f --key /etc/certidude/authority/{{ session.authority.hostname }}/host_key.pem --cert /etc/certidude/authority/{{ session.authority.hostname }}/host_cert.pem --cacert /etc/certidude/authority/{{ session.authority.hostname }}/ca_cert.pem https://{{ session.authority.hostname }}:8443/api/lease/" | CURL="curl --cert-status -m 3 -f --key /etc/certidude/authority/{{ session.authority.hostname }}/host_key.pem --cert /etc/certidude/authority/{{ session.authority.hostname }}/host_cert.pem --cacert /etc/certidude/authority/{{ session.authority.hostname }}/ca_cert.pem https://{{ session.authority.hostname }}:8443/api/lease/" | ||||||
| 
 | 
 | ||||||
| case $PLUTO_VERB in | case $PLUTO_VERB in | ||||||
|     up-client) $CURL --data-urlencode "outer_address=$PLUTO_PEER" --data-urlencode "inner_address=$PLUTO_PEER_SOURCEIP" --data-urlencode "client=$PLUTO_PEER_ID" ;; |     up-client) $CURL --data-urlencode "outer_address=$PLUTO_PEER" --data-urlencode "inner_address=$PLUTO_PEER_SOURCEIP" --data-urlencode "client=$PLUTO_PEER_ID" ;; | ||||||
| @@ -1,8 +1,8 @@ | |||||||
| 
 | 
 | ||||||
| server { | server { | ||||||
|     listen 80; |     listen 80; | ||||||
|     server_name {{common_name}}; |     server_name {{ common_name }}; | ||||||
|     rewrite ^ https://{{common_name}}$request_uri?; |     rewrite ^ https://{{ common_name }}\$request_uri?; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| server { | server { | ||||||
| @@ -10,19 +10,21 @@ server { | |||||||
|     add_header X-Frame-Options "DENY"; |     add_header X-Frame-Options "DENY"; | ||||||
|     add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; |     add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; | ||||||
|     listen 443 ssl; |     listen 443 ssl; | ||||||
|     server_name {{common_name}}; |     server_name $NAME; | ||||||
|     client_max_body_size 10G; |     client_max_body_size 10G; | ||||||
|     ssl_certificate {{certificate_path}}; |     ssl_certificate {{certificate_path}}; | ||||||
|     ssl_certificate_key {{key_path}}; |     ssl_certificate_key {{key_path}}; | ||||||
|     ssl_client_certificate {{authority_path}}; |     ssl_client_certificate {{authority_path}}; | ||||||
|     ssl_crl {{revocations_path}}; |  | ||||||
|     ssl_verify_client {{verify_client}}; |  | ||||||
| 
 | 
 | ||||||
|     location ~ \.php$ { |     # Uncomment following to enable mutual authentication with certificates | ||||||
|  |     #ssl_crl {{revocations_path}}; | ||||||
|  |     #ssl_verify_client on; | ||||||
|  | 
 | ||||||
|  |     location ~ \.php\$ { | ||||||
|         fastcgi_split_path_info ^(.+\.php)(/.+)$; |         fastcgi_split_path_info ^(.+\.php)(/.+)$; | ||||||
|         fastcgi_pass unix:/run/php5-fpm.sock; |         fastcgi_pass unix:/run/php5-fpm.sock; | ||||||
|         fastcgi_index index.php; |         fastcgi_index index.php; | ||||||
|         fastcgi_param REMOTE_USER $ssl_client_s_dn_cn; |         fastcgi_param REMOTE_USER \$ssl_client_s_dn_cn; | ||||||
|         include fastcgi_params; |         include fastcgi_params; | ||||||
|     } |     } | ||||||
| } | } | ||||||
							
								
								
									
										7
									
								
								certidude/templates/snippets/nginx-ocsp-cache.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								certidude/templates/snippets/nginx-ocsp-cache.service
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | [Unit] | ||||||
|  | Description=Cache OCSP responses for nginx OCSP stapling | ||||||
|  |  | ||||||
|  | [Service] | ||||||
|  | Type=oneshot | ||||||
|  | Requires=nginx.service | ||||||
|  | ExecStart=-/usr/bin/curl --cert-status https://{{ common_name }}:8443/ --cacert /etc/certidude/authority/{{ session.authority.hostname }}/ca_cert.pem | ||||||
							
								
								
									
										3
									
								
								certidude/templates/snippets/nginx-ocsp-cache.timer
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								certidude/templates/snippets/nginx-ocsp-cache.timer
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | [Timer] | ||||||
|  | OnCalendar=*:0/15 | ||||||
|  | Persistent=true | ||||||
| @@ -8,9 +8,6 @@ ssl_ecdh_curve secp384r1; | |||||||
| ssl_session_timeout  10m; | ssl_session_timeout  10m; | ||||||
| ssl_session_cache shared:SSL:10m; | ssl_session_cache shared:SSL:10m; | ||||||
| ssl_session_tickets off; | ssl_session_tickets off; | ||||||
| ssl_trusted_certificate {{ ca_cert }}; # OCSP responder trust chain |  | ||||||
| ssl_stapling on; |  | ||||||
| ssl_stapling_verify on; |  | ||||||
| add_header X-Frame-Options DENY; | add_header X-Frame-Options DENY; | ||||||
| add_header X-Content-Type-Options nosniff; | add_header X-Content-Type-Options nosniff; | ||||||
| add_header X-XSS-Protection "1; mode=block"; | add_header X-XSS-Protection "1; mode=block"; | ||||||
| @@ -23,6 +20,6 @@ add_header X-Robots-Tag none; | |||||||
| # Add SSLUserName SSL_CLIENT_S_DN_CN style parameter support | # Add SSLUserName SSL_CLIENT_S_DN_CN style parameter support | ||||||
| map $ssl_client_s_dn  $ssl_client_s_dn_cn { | map $ssl_client_s_dn  $ssl_client_s_dn_cn { | ||||||
|     default           ""; |     default           ""; | ||||||
|     ~/CN=(?<CN>[^/]+) $CN; |     ~/CN=([^/]+) $1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
							
								
								
									
										0
									
								
								certidude/templates/snippets/ocsp-cache@.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								certidude/templates/snippets/ocsp-cache@.service
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										7
									
								
								certidude/templates/snippets/request-server.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								certidude/templates/snippets/request-server.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | # Use fully qualified name | ||||||
|  | test -e /sbin/uci && NAME=$(nslookup $(uci get network.wan.ipaddr) |  grep "name =" | head -n1 | cut -d "=" -f 2 | xargs) | ||||||
|  | test -e /bin/hostname && NAME=$(hostname -f) | ||||||
|  | test -n "$NAME" || NAME=$(cat /proc/sys/kernel/hostname) | ||||||
|  |  | ||||||
|  | {% include "snippets/request-common.sh" %} | ||||||
|  | {% include "snippets/submit-request-wait.sh" %} | ||||||
							
								
								
									
										11
									
								
								certidude/templates/snippets/setup-ocsp-caching.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								certidude/templates/snippets/setup-ocsp-caching.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | # See more on http://unmitigatedrisk.com/?p=241 why we're doing this | ||||||
|  | cat << EOF > /etc/systemd/system/nginx-ocsp-cache.service | ||||||
|  | {% include "snippets/nginx-ocsp-cache.service" %}EOF | ||||||
|  |  | ||||||
|  | cat << EOF > /etc/systemd/system/nginx-ocsp-cache.timer | ||||||
|  | {% include "snippets/nginx-ocsp-cache.timer" %}EOF | ||||||
|  |  | ||||||
|  | systemctl enable nginx-ocsp-cache.service | ||||||
|  | systemctl enable nginx-ocsp-cache.timer | ||||||
|  | systemctl start nginx-ocsp-cache.service | ||||||
|  | systemctl start nginx-ocsp-cache.timer | ||||||
| @@ -1,9 +1,3 @@ | |||||||
| # Use fully qualified name |  | ||||||
| test -e /sbin/uci && NAME=$(nslookup $(uci get network.wan.ipaddr) |  grep "name =" | head -n1 | cut -d "=" -f 2 | xargs) |  | ||||||
| test -e /bin/hostname && NAME=$(hostname -f) |  | ||||||
| test -n "$NAME" || NAME=$(cat /proc/sys/kernel/hostname) |  | ||||||
| 
 |  | ||||||
| {% include "snippets/request-common.sh" %} |  | ||||||
| # Submit CSR and save signed certificate | # Submit CSR and save signed certificate | ||||||
| curl --cert-status -f -L -H "Content-type: application/pkcs10" \ | curl --cert-status -f -L -H "Content-type: application/pkcs10" \ | ||||||
|     --cacert /etc/certidude/authority/{{ session.authority.hostname }}/ca_cert.pem \ |     --cacert /etc/certidude/authority/{{ session.authority.hostname }}/ca_cert.pem \ | ||||||
| @@ -5,12 +5,14 @@ test -e /etc/pki/ca-trust/source/anchors \ | |||||||
| 
 | 
 | ||||||
| # Insert into Ubuntu trust store, only applies to curl | # Insert into Ubuntu trust store, only applies to curl | ||||||
| test -e /usr/local/share/ca-certificates/ \ | test -e /usr/local/share/ca-certificates/ \ | ||||||
|  && ln -s /etc/certidude/authority/{{ session.authority.hostname }}/ca_cert.pem /usr/local/share/ca-certificates/{{ session.authority.hostname }}.crt \ |  && ln -f -s /etc/certidude/authority/{{ session.authority.hostname }}/ca_cert.pem /usr/local/share/ca-certificates/{{ session.authority.hostname }}.crt \ | ||||||
|  && update-ca-certificates |  && update-ca-certificates | ||||||
| 
 | 
 | ||||||
| # Patch Firefox trust store on Ubuntu | # Patch Firefox trust store on Ubuntu | ||||||
| if [ ! -h /usr/lib/firefox/libnssckbi.so ]; then | if [ -d /usr/lib/firefox ]; then | ||||||
|   apt install p11-kit p11-kit-modules |   if [ ! -h /usr/lib/firefox/libnssckbi.so ]; then | ||||||
|   mv /usr/lib/firefox/libnssckbi.so /usr/lib/firefox/libnssckbi.so.bak |     apt install -y p11-kit p11-kit-modules | ||||||
|   ln -s /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so /usr/lib/firefox/libnssckbi.so |     mv /usr/lib/firefox/libnssckbi.so /usr/lib/firefox/libnssckbi.so.bak | ||||||
|  |     ln -s /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so /usr/lib/firefox/libnssckbi.so | ||||||
|  |   fi | ||||||
| fi | fi | ||||||
| @@ -19,6 +19,10 @@ | |||||||
|             <a class="nav-link" id="contact-tab" data-toggle="tab" href="#snippet-unix" role="tab" aria-controls="unix" aria-selected="false">UNIX</a> |             <a class="nav-link" id="contact-tab" data-toggle="tab" href="#snippet-unix" role="tab" aria-controls="unix" aria-selected="false">UNIX</a> | ||||||
|           </li> |           </li> | ||||||
| 
 | 
 | ||||||
|  |           <li class="nav-item"> | ||||||
|  |             <a class="nav-link" id="contact-tab" data-toggle="tab" href="#snippet-nginx" role="tab" aria-controls="nginx" aria-selected="false">nginx</a> | ||||||
|  |           </li> | ||||||
|  | 
 | ||||||
|           {% if "openvpn" in session.service.protocols %} |           {% if "openvpn" in session.service.protocols %} | ||||||
|             <li class="nav-item"> |             <li class="nav-item"> | ||||||
|               <a class="nav-link" id="contact-tab" data-toggle="tab" href="#snippet-openvpn" role="tab" aria-controls="openvpn" aria-selected="false">OpenVPN</a> |               <a class="nav-link" id="contact-tab" data-toggle="tab" href="#snippet-openvpn" role="tab" aria-controls="openvpn" aria-selected="false">OpenVPN</a> | ||||||
| @@ -69,24 +73,48 @@ | |||||||
| 
 | 
 | ||||||
|           <!-- UNIX-like --> |           <!-- UNIX-like --> | ||||||
|           <div class="tab-pane fade" id="snippet-unix" role="tabpanel" aria-labelledby="unix"> |           <div class="tab-pane fade" id="snippet-unix" role="tabpanel" aria-labelledby="unix"> | ||||||
| 
 |  | ||||||
|             <p>For client certificates generate key pair and submit the signing request with common name set to short hostname:</p> |             <p>For client certificates generate key pair and submit the signing request with common name set to short hostname:</p> | ||||||
|             <div class="highlight"> |             <div class="highlight"> | ||||||
| 
 |  | ||||||
|               <pre class="code"><code>{% include "snippets/request-client.sh" %}</code></pre> |               <pre class="code"><code>{% include "snippets/request-client.sh" %}</code></pre> | ||||||
|             </div> |             </div> | ||||||
| 
 |  | ||||||
|             <p>For server certificates use fully qualified hostname as common name and sign request accordingly:</p> |  | ||||||
|             <div class="highlight"> |  | ||||||
|               <pre class="code"><code>{% include "snippets/request-server.sh" %}</code></pre> |  | ||||||
|             </div> |  | ||||||
| 
 |  | ||||||
|             <p>To renew:</p> |             <p>To renew:</p> | ||||||
|             <div class="highlight"> |             <div class="highlight"> | ||||||
|             <pre class="code"><code>{% include "snippets/renew.sh" %}</code></pre> |             <pre class="code"><code>{% include "snippets/renew.sh" %}</code></pre> | ||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
| 
 | 
 | ||||||
|  |           <!-- nginx --> | ||||||
|  |           <div class="tab-pane fade" id="snippet-nginx" role="tabpanel" aria-labelledby="nginx"> | ||||||
|  |             <p>For server certificates use fully qualified hostname as common name and sign request accordingly:</p> | ||||||
|  |             <div class="highlight"> | ||||||
|  |               <pre class="code"><code>apt install -y nginx curl | ||||||
|  | NAME=$(hostname -f) | ||||||
|  | {% include "snippets/request-common.sh" %} | ||||||
|  | {% include "snippets/submit-request-wait.sh" %} | ||||||
|  | {% include "snippets/setup-ocsp-caching.sh" %} | ||||||
|  | 
 | ||||||
|  | cat << \EOF > /etc/nginx/conf.d/tls.conf | ||||||
|  | {% include "snippets/nginx-tls.conf" %}EOF | ||||||
|  | 
 | ||||||
|  | cat << EOF > /etc/nginx/sites-available/https.conf | ||||||
|  | {% include "snippets/nginx-https-site.conf" %}EOF | ||||||
|  | 
 | ||||||
|  | test -h /etc/nginx/sites-enabled/https.conf \ | ||||||
|  |  || ln -s ../sites-available/https.conf /etc/nginx/sites-enabled/https.conf | ||||||
|  | rm -fv /etc/nginx/sites-enabled/default | ||||||
|  | test -e {{ dhparam_path }} \ | ||||||
|  |  || openssl dhparam -out {{ dhparam_path }} 2048 | ||||||
|  | 
 | ||||||
|  | systemctl reload nginx | ||||||
|  | </code></pre> | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |             <p>To renew create cron weekly job:</p> | ||||||
|  |             <div class="highlight"> | ||||||
|  |               <pre class="code"><code>{% include "snippets/renew.sh" %}</code></pre> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  | 
 | ||||||
|           <!-- OpenVPN as client --> |           <!-- OpenVPN as client --> | ||||||
|           <div class="tab-pane fade" id="snippet-openvpn" role="tabpanel" aria-labelledby="openvpn"> |           <div class="tab-pane fade" id="snippet-openvpn" role="tabpanel" aria-labelledby="openvpn"> | ||||||
|             <p>First acquire certificates using the snippet above.</p> |             <p>First acquire certificates using the snippet above.</p> | ||||||
| @@ -5,4 +5,4 @@ at | |||||||
| <a target="_blank" href="http://{{ certificate.lease.inner_address }}">{{ certificate.lease.inner_address }}</a>{% if certificate.lease.outer_address %} | <a target="_blank" href="http://{{ certificate.lease.inner_address }}">{{ certificate.lease.inner_address }}</a>{% if certificate.lease.outer_address %} | ||||||
| from | from | ||||||
| <a target="{{ certificate.lease.outer_address }}" href="https://geoiplookup.net/ip/{{ certificate.lease.outer_address }}">{{ certificate.lease.outer_address }}</a>{% endif %}. | <a target="{{ certificate.lease.outer_address }}" href="https://geoiplookup.net/ip/{{ certificate.lease.outer_address }}">{{ certificate.lease.outer_address }}</a>{% endif %}. | ||||||
| 
 | See some stats <a href="http://172.20.1.19:19999/host/{{ certificate.common_name }}/" target="_blank">here</a>. | ||||||
| @@ -75,7 +75,7 @@ | |||||||
| 
 | 
 | ||||||
|       <div class="bd-example"> |       <div class="bd-example"> | ||||||
|         <pre><code class="language-sh" data-lang="sh">wget <a href="/api/signed/{{ certificate.common_name }}/">http://{{ session.authority.hostname }}/api/signed/{{ certificate.common_name }}/</a> |         <pre><code class="language-sh" data-lang="sh">wget <a href="/api/signed/{{ certificate.common_name }}/">http://{{ session.authority.hostname }}/api/signed/{{ certificate.common_name }}/</a> | ||||||
| curl --cert-status http://{{ session.authority.hostname }}/api/signed/{{ certificate.common_name }}/ \ | curl http://{{ session.authority.hostname }}/api/signed/{{ certificate.common_name }}/ \ | ||||||
|   | openssl x509 -text -noout</code></pre> |   | openssl x509 -text -noout</code></pre> | ||||||
|       </div> |       </div> | ||||||
| 
 | 
 | ||||||
| @@ -273,15 +273,16 @@ def test_cli_setup_authority(): | |||||||
|     # - SCEP disabled |     # - SCEP disabled | ||||||
|     # - CRL enabled |     # - CRL enabled | ||||||
|  |  | ||||||
|     assert os.system("certidude setup authority --elliptic-curve") == 0 |     assert os.system("certidude provision authority --elliptic-curve") == 0 | ||||||
|  |  | ||||||
|     assert_cleanliness() |     assert_cleanliness() | ||||||
|  |  | ||||||
|     assert os.path.exists("/var/lib/certidude/signed/ca.example.lan.pem"), "provisioning failed" |     assert os.path.exists("/var/lib/certidude/signed/ca.example.lan.pem"), "provisioning failed" | ||||||
|  |  | ||||||
|     # Make sure nginx is running |     # Make sure nginx is running | ||||||
|  |     os.system("systemctl restart certidude-backend") | ||||||
|  |     os.system("systemctl start certidude-ocsp-cache.service") | ||||||
|     assert os.system("nginx -t") == 0, "invalid nginx configuration" |     assert os.system("nginx -t") == 0, "invalid nginx configuration" | ||||||
|     os.system("systemctl restart certidude") |  | ||||||
|     os.system("systemctl restart nginx") |     os.system("systemctl restart nginx") | ||||||
|     assert os.path.exists("/run/nginx.pid"), "nginx wasn't started up properly" |     assert os.path.exists("/run/nginx.pid"), "nginx wasn't started up properly" | ||||||
|  |  | ||||||
| @@ -638,7 +639,7 @@ def test_cli_setup_authority(): | |||||||
|     # Test tagging integration in scripting framework |     # Test tagging integration in scripting framework | ||||||
|     r = client().simulate_get("/api/signed/test/script/") |     r = client().simulate_get("/api/signed/test/script/") | ||||||
|     assert r.status_code == 200, r.text # script render ok |     assert r.status_code == 200, r.text # script render ok | ||||||
|     assert "curl https://ca.example.lan:8443/api/signed/test/attr " in r.text, r.text |     assert "curl --cert-status https://ca.example.lan:8443/api/signed/test/attr " in r.text, r.text | ||||||
|     assert "Tartu" in r.text, r.text |     assert "Tartu" in r.text, r.text | ||||||
|  |  | ||||||
|     r = client().simulate_post("/api/signed/test/tag/", |     r = client().simulate_post("/api/signed/test/tag/", | ||||||
| @@ -751,13 +752,13 @@ def test_cli_setup_authority(): | |||||||
|  |  | ||||||
|     clean_client() |     clean_client() | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ["setup", "nginx", "-cn", "www", "ca.example.lan"]) |     result = runner.invoke(cli, ["provision", "nginx", "-cn", "www", "ca.example.lan"]) | ||||||
|     assert result.exception |     assert result.exception | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ["setup", "nginx", "-cn", "www.example.lan", "ca.example.lan"]) |     result = runner.invoke(cli, ["provision", "nginx", "-cn", "www.example.lan", "ca.example.lan"]) | ||||||
|     assert not result.exception, result.output |     assert not result.exception, result.output | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ["setup", "nginx", "-cn", "www.example.lan", "ca.example.lan"]) |     result = runner.invoke(cli, ["provision", "nginx", "-cn", "www.example.lan", "ca.example.lan"]) | ||||||
|     assert not result.exception, result.output # client conf already exists, remove to regenerate |     assert not result.exception, result.output # client conf already exists, remove to regenerate | ||||||
|  |  | ||||||
|     with open("/etc/certidude/client.conf", "a") as fh: |     with open("/etc/certidude/client.conf", "a") as fh: | ||||||
| @@ -806,13 +807,13 @@ def test_cli_setup_authority(): | |||||||
|     if not os.path.exists("/etc/openvpn/keys"): |     if not os.path.exists("/etc/openvpn/keys"): | ||||||
|         os.makedirs("/etc/openvpn/keys") |         os.makedirs("/etc/openvpn/keys") | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'openvpn', 'server', "-cn", "vpn", "ca.example.lan"]) |     result = runner.invoke(cli, ['provision', 'openvpn', 'server', "-cn", "vpn", "ca.example.lan"]) | ||||||
|     assert result.exception, result.output |     assert result.exception, result.output | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'openvpn', 'server', "-cn", "vpn.example.lan", "ca.example.lan"]) |     result = runner.invoke(cli, ['provision', 'openvpn', 'server', "-cn", "vpn.example.lan", "ca.example.lan"]) | ||||||
|     assert not result.exception, result.output |     assert not result.exception, result.output | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'openvpn', 'server', "-cn", "vpn.example.lan", "ca.example.lan"]) |     result = runner.invoke(cli, ['provision', 'openvpn', 'server', "-cn", "vpn.example.lan", "ca.example.lan"]) | ||||||
|     assert not result.exception, result.output # client conf already exists, remove to regenerate |     assert not result.exception, result.output # client conf already exists, remove to regenerate | ||||||
|  |  | ||||||
|     with open("/etc/certidude/client.conf", "a") as fh: |     with open("/etc/certidude/client.conf", "a") as fh: | ||||||
| @@ -849,10 +850,10 @@ def test_cli_setup_authority(): | |||||||
|     os.unlink("/etc/certidude/client.conf") |     os.unlink("/etc/certidude/client.conf") | ||||||
|     os.unlink("/etc/certidude/services.conf") |     os.unlink("/etc/certidude/services.conf") | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'openvpn', 'client', "-cn", "roadwarrior1", "ca.example.lan", "vpn.example.lan"]) |     result = runner.invoke(cli, ['provision', 'openvpn', 'client', "-cn", "roadwarrior1", "ca.example.lan", "vpn.example.lan"]) | ||||||
|     assert not result.exception, result.output |     assert not result.exception, result.output | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'openvpn', 'client', "-cn", "roadwarrior1", "ca.example.lan", "vpn.example.lan"]) |     result = runner.invoke(cli, ['provision', 'openvpn', 'client', "-cn", "roadwarrior1", "ca.example.lan", "vpn.example.lan"]) | ||||||
|     assert not result.exception, result.output # client conf already exists, remove to regenerate |     assert not result.exception, result.output # client conf already exists, remove to regenerate | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"]) |     result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"]) | ||||||
| @@ -866,7 +867,7 @@ def test_cli_setup_authority(): | |||||||
|  |  | ||||||
|     clean_client() |     clean_client() | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'openvpn', 'networkmanager', "-cn", "roadwarrior3", "ca.example.lan", "vpn.example.lan"]) |     result = runner.invoke(cli, ['provision', 'openvpn', 'networkmanager', "-cn", "roadwarrior3", "ca.example.lan", "vpn.example.lan"]) | ||||||
|     assert not result.exception, result.output |     assert not result.exception, result.output | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"]) |     result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"]) | ||||||
| @@ -1116,16 +1117,16 @@ def test_cli_setup_authority(): | |||||||
|     clean_client() |     clean_client() | ||||||
|     assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") |     assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'strongswan', 'server', "-cn", "ipsec", "ca.example.lan"]) |     result = runner.invoke(cli, ['provision', 'strongswan', 'server', "-cn", "ipsec", "ca.example.lan"]) | ||||||
|     assert result.exception, result.output # FQDN required |     assert result.exception, result.output # FQDN required | ||||||
|     assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") |     assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'strongswan', 'server', "-cn", "ipsec.example.lan", "ca.example.lan"]) |     result = runner.invoke(cli, ['provision', 'strongswan', 'server', "-cn", "ipsec.example.lan", "ca.example.lan"]) | ||||||
|     assert not result.exception, result.output |     assert not result.exception, result.output | ||||||
|     assert open("/etc/ipsec.secrets").read() == ": RSA /etc/certidude/authority/ca.example.lan/server_key.pem\n" |     assert open("/etc/ipsec.secrets").read() == ": RSA /etc/certidude/authority/ca.example.lan/server_key.pem\n" | ||||||
|     assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") |     assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'strongswan', 'server', "-cn", "ipsec.example.lan", "ca.example.lan"]) |     result = runner.invoke(cli, ['provision', 'strongswan', 'server', "-cn", "ipsec.example.lan", "ca.example.lan"]) | ||||||
|     assert not result.exception, result.output # client conf already exists, remove to regenerate |     assert not result.exception, result.output # client conf already exists, remove to regenerate | ||||||
|     assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") |     assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") | ||||||
|  |  | ||||||
| @@ -1162,10 +1163,10 @@ def test_cli_setup_authority(): | |||||||
|     os.unlink("/etc/certidude/client.conf") |     os.unlink("/etc/certidude/client.conf") | ||||||
|     os.unlink("/etc/certidude/services.conf") |     os.unlink("/etc/certidude/services.conf") | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'strongswan', 'client', "-cn", "roadwarrior2", "ca.example.lan", "ipsec.example.lan"]) |     result = runner.invoke(cli, ['provision', 'strongswan', 'client', "-cn", "roadwarrior2", "ca.example.lan", "ipsec.example.lan"]) | ||||||
|     assert not result.exception, result.output |     assert not result.exception, result.output | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'strongswan', 'client', "-cn", "roadwarrior2", "ca.example.lan", "ipsec.example.lan"]) |     result = runner.invoke(cli, ['provision', 'strongswan', 'client', "-cn", "roadwarrior2", "ca.example.lan", "ipsec.example.lan"]) | ||||||
|     assert not result.exception, result.output # client conf already exists, remove to regenerate |     assert not result.exception, result.output # client conf already exists, remove to regenerate | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"]) |     result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"]) | ||||||
| @@ -1178,7 +1179,7 @@ def test_cli_setup_authority(): | |||||||
|  |  | ||||||
|     clean_client() |     clean_client() | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ['setup', 'strongswan', 'networkmanager', "-cn", "roadwarrior4", "ca.example.lan", "ipsec.example.lan"]) |     result = runner.invoke(cli, ['provision', 'strongswan', 'networkmanager', "-cn", "roadwarrior4", "ca.example.lan", "ipsec.example.lan"]) | ||||||
|     assert not result.exception, result.output |     assert not result.exception, result.output | ||||||
|  |  | ||||||
|     result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"]) |     result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"]) | ||||||
| @@ -1257,7 +1258,7 @@ def test_cli_setup_authority(): | |||||||
|  |  | ||||||
|     assert os.path.exists("/run/certidude/server.pid") |     assert os.path.exists("/run/certidude/server.pid") | ||||||
|     pid_certidude = int(open("/run/certidude/server.pid").read()) |     pid_certidude = int(open("/run/certidude/server.pid").read()) | ||||||
|     os.system("systemctl stop certidude") |     os.system("systemctl stop certidude-backend") | ||||||
|     assert not os.path.exists("/run/certidude/server.pid") |     assert not os.path.exists("/run/certidude/server.pid") | ||||||
|  |  | ||||||
|     # Install packages |     # Install packages | ||||||
| @@ -1321,16 +1322,13 @@ def test_cli_setup_authority(): | |||||||
|     # Bootstrap authority again with: |     # Bootstrap authority again with: | ||||||
|     # - RSA certificates |     # - RSA certificates | ||||||
|     # - Kerberos auth |     # - Kerberos auth | ||||||
|     # - OCSP disabled |  | ||||||
|     # - SCEP enabled |     # - SCEP enabled | ||||||
|     # - CRL disabled |     # - CRL disabled | ||||||
|  |  | ||||||
|     assert not os.path.exists("/var/lib/certidude/ca_key.pem") |     assert not os.path.exists("/var/lib/certidude/ca_key.pem") | ||||||
|     assert os.system("certidude setup authority --skip-packages -o 'Demola LLC'") == 0 |     os.unlink("/etc/certidude/authority/ca.example.lan/ca_cert.pem") | ||||||
|  |     assert os.system("certidude provision authority --skip-packages -o 'Demola LLC'") == 0 | ||||||
|     assert os.path.exists("/var/lib/certidude/ca_key.pem") |     assert os.path.exists("/var/lib/certidude/ca_key.pem") | ||||||
|     assert os.path.exists("/etc/cron.daily/certidude") |  | ||||||
|     assert os.path.exists("/etc/cron.hourly/certidude") |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     # Make modifications to /etc/certidude/server.conf so |     # Make modifications to /etc/certidude/server.conf so | ||||||
|     # Certidude would auth against domain controller |     # Certidude would auth against domain controller | ||||||
| @@ -1339,18 +1337,17 @@ def test_cli_setup_authority(): | |||||||
|     assert os.system("sed -e 's/autosign subnets =.*/autosign subnets =/g' -i /etc/certidude/server.conf") == 0 |     assert os.system("sed -e 's/autosign subnets =.*/autosign subnets =/g' -i /etc/certidude/server.conf") == 0 | ||||||
|     assert os.system("sed -e 's/machine enrollment subnets =.*/machine enrollment subnets = 0.0.0.0\\/0/g' -i /etc/certidude/server.conf") == 0 |     assert os.system("sed -e 's/machine enrollment subnets =.*/machine enrollment subnets = 0.0.0.0\\/0/g' -i /etc/certidude/server.conf") == 0 | ||||||
|     assert os.system("sed -e 's/scep subnets =.*/scep subnets = 0.0.0.0\\/0/g' -i /etc/certidude/server.conf") == 0 |     assert os.system("sed -e 's/scep subnets =.*/scep subnets = 0.0.0.0\\/0/g' -i /etc/certidude/server.conf") == 0 | ||||||
|     assert os.system("sed -e 's/ocsp subnets =.*/ocsp subnets =/g' -i /etc/certidude/server.conf") == 0 |  | ||||||
|     assert os.system("sed -e 's/crl subnets =.*/crl subnets =/g' -i /etc/certidude/server.conf") == 0 |     assert os.system("sed -e 's/crl subnets =.*/crl subnets =/g' -i /etc/certidude/server.conf") == 0 | ||||||
|     assert os.system("sed -e 's/address = certificates@example.lan/address =/g' -i /etc/certidude/server.conf") == 0 |     assert os.system("sed -e 's/address = certificates@example.lan/address =/g' -i /etc/certidude/server.conf") == 0 | ||||||
|     assert os.system("sed -e 's/kerberos subnets =.*/kerberos subnets = 0.0.0.0\\/0/g' -i /etc/certidude/server.conf") == 0 |     assert os.system("sed -e 's/kerberos subnets =.*/kerberos subnets = 0.0.0.0\\/0/g' -i /etc/certidude/server.conf") == 0 | ||||||
|  |  | ||||||
|     # Update server credential cache |     # Update server credential cache | ||||||
|     assert os.system("/etc/cron.hourly/certidude") == 0 |     assert os.system("systemctl start certidude-ldap-kinit") == 0 | ||||||
|     assert os.path.exists("/run/certidude/krb5cc") |     assert os.path.exists("/run/certidude/krb5cc") | ||||||
|     assert os.stat("/run/certidude/krb5cc").st_uid != 0, "Incorrect persmissions for /run/certidude/krb5cc" |     assert os.stat("/run/certidude/krb5cc").st_uid != 0, "Incorrect persmissions for /run/certidude/krb5cc" | ||||||
|  |  | ||||||
|     # Start certidude backend |     # Start certidude backend | ||||||
|     assert os.system("systemctl restart certidude") == 0 |     assert os.system("systemctl restart certidude-backend") == 0 | ||||||
|  |  | ||||||
|     cov_finished = False |     cov_finished = False | ||||||
|     for path in os.listdir("/tmp/"): |     for path in os.listdir("/tmp/"): | ||||||
| @@ -1393,14 +1390,6 @@ def test_cli_setup_authority(): | |||||||
|     r = requests.post("http://ca.example.lan/api/scep/") |     r = requests.post("http://ca.example.lan/api/scep/") | ||||||
|     assert r.status_code == 405 |     assert r.status_code == 405 | ||||||
|  |  | ||||||
|     # OCSP should be disabled now |  | ||||||
|     r = requests.get("http://ca.example.lan/api/ocsp/") |  | ||||||
|     assert r.status_code == 404 |  | ||||||
|     r = requests.post("http://ca.example.lan/api/ocsp/") |  | ||||||
|     assert r.status_code == 404 |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     ##################### |     ##################### | ||||||
|     ### Kerberos auth ### |     ### Kerberos auth ### | ||||||
| @@ -1460,7 +1449,7 @@ def test_cli_setup_authority(): | |||||||
|         clean_client() |         clean_client() | ||||||
|  |  | ||||||
|         # Test non-matching CN |         # Test non-matching CN | ||||||
|         result = runner.invoke(cli, ['setup', 'openvpn', 'client', "-cn", "somethingelse", "ca.example.lan", "vpn.example.lan"]) |         result = runner.invoke(cli, ['provision', 'openvpn', 'client', "-cn", "somethingelse", "ca.example.lan", "vpn.example.lan"]) | ||||||
|         assert not result.exception, result.output |         assert not result.exception, result.output | ||||||
|  |  | ||||||
|         result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait", "--kerberos"]) |         result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait", "--kerberos"]) | ||||||
| @@ -1469,7 +1458,7 @@ def test_cli_setup_authority(): | |||||||
|         # With matching CN it should work |         # With matching CN it should work | ||||||
|         clean_client() |         clean_client() | ||||||
|  |  | ||||||
|         result = runner.invoke(cli, ['setup', 'openvpn', 'client', "-cn", "ca", "ca.example.lan", "vpn.example.lan"]) |         result = runner.invoke(cli, ['provision', 'openvpn', 'client', "-cn", "ca", "ca.example.lan", "vpn.example.lan"]) | ||||||
|         assert not result.exception, result.output |         assert not result.exception, result.output | ||||||
|  |  | ||||||
|         result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait", "--kerberos"]) |         result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait", "--kerberos"]) | ||||||
| @@ -1509,7 +1498,7 @@ def test_cli_setup_authority(): | |||||||
|     assert not result.exception, result.output |     assert not result.exception, result.output | ||||||
|  |  | ||||||
|     pid_certidude = int(open("/run/certidude/server.pid").read()) |     pid_certidude = int(open("/run/certidude/server.pid").read()) | ||||||
|     assert os.system("systemctl stop certidude") == 0 |     assert os.system("systemctl stop certidude-backend") == 0 | ||||||
|  |  | ||||||
|     cov_finished = False |     cov_finished = False | ||||||
|     for path in os.listdir("/tmp/"): |     for path in os.listdir("/tmp/"): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user