mirror of
				https://github.com/laurivosandi/certidude
				synced 2025-10-31 09:29:13 +00:00 
			
		
		
		
	Allow provisioning as subordinate CA and add offline install docs
This commit is contained in:
		
							
								
								
									
										93
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								README.rst
									
									
									
									
									
								
							| @@ -60,6 +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 | ||||||
| * `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. | ||||||
| @@ -93,12 +94,8 @@ System dependencies for Ubuntu 16.04: | |||||||
|  |  | ||||||
| .. code:: bash | .. code:: bash | ||||||
|  |  | ||||||
|     apt install -y \ |     apt install -y python3-click python3-jinja2 python3-markdown \ | ||||||
|         python3-click \ |         python3-pip python3-mysql.connector python3-requests python3-pyxattr | ||||||
|         python3-jinja2 python3-markdown \ |  | ||||||
|         python3-pip \ |  | ||||||
|         python3-mysql.connector python3-requests \ |  | ||||||
|         python3-pyxattr |  | ||||||
|  |  | ||||||
| System dependencies for Fedora 25+: | System dependencies for Fedora 25+: | ||||||
|  |  | ||||||
| @@ -122,7 +119,6 @@ You can check it with: | |||||||
|     hostname -f |     hostname -f | ||||||
|  |  | ||||||
| The command should return ``ca.example.com``. | The command should return ``ca.example.com``. | ||||||
|  |  | ||||||
| If necessary tweak machine's fully qualified hostname in ``/etc/hosts``: | If necessary tweak machine's fully qualified hostname in ``/etc/hosts``: | ||||||
|  |  | ||||||
| .. code:: | .. code:: | ||||||
| @@ -130,8 +126,15 @@ If necessary tweak machine's fully qualified hostname in ``/etc/hosts``: | |||||||
|     127.0.0.1 localhost |     127.0.0.1 localhost | ||||||
|     127.0.1.1 ca.example.com ca |     127.0.1.1 ca.example.com ca | ||||||
|  |  | ||||||
|  | Certidude will submit e-mail notifications to locally running MTA. | ||||||
|  | Install Postfix and configure it as Satellite system: | ||||||
|  |  | ||||||
|  | .. code:: bash | ||||||
|  |  | ||||||
|  |     apt install postfix | ||||||
|  |  | ||||||
| Certidude can set up certificate authority relatively easily. | Certidude can set up certificate authority relatively easily. | ||||||
| Following will set up certificate authority in ``/var/lib/certidude/hostname.domain.tld``, | Following will set up certificate authority in ``/var/lib/certidude/``, | ||||||
| configure systemd service for your platform, | configure systemd service for your platform, | ||||||
| nginx in ``/etc/nginx/sites-available/certidude.conf``, | nginx in ``/etc/nginx/sites-available/certidude.conf``, | ||||||
| cronjobs in ``/etc/cron.hourly/certidude`` and much more: | cronjobs in ``/etc/cron.hourly/certidude`` and much more: | ||||||
| @@ -140,20 +143,13 @@ cronjobs in ``/etc/cron.hourly/certidude`` and much more: | |||||||
|  |  | ||||||
|     certidude setup authority |     certidude setup 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, | ||||||
| and start the services: | to apply changes run: | ||||||
|  |  | ||||||
| .. code:: bash | .. code:: bash | ||||||
|  |  | ||||||
|     systemctl restart certidude |     systemctl restart certidude | ||||||
|  |  | ||||||
| Certidude will submit e-mail notifications to locally running MTA. |  | ||||||
| Install Postfix and configure it as Satellite system: |  | ||||||
|  |  | ||||||
| .. code:: bash |  | ||||||
|  |  | ||||||
|     apt install postfix |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Setting up PAM authentication | Setting up PAM authentication | ||||||
| ----------------------------- | ----------------------------- | ||||||
| @@ -247,7 +243,6 @@ Setting up services | |||||||
| ------------------- | ------------------- | ||||||
|  |  | ||||||
| Set up services as usual (OpenVPN, Strongswan, etc), when setting up certificates | Set up services as usual (OpenVPN, Strongswan, etc), when setting up certificates | ||||||
| generate signing request with TLS server flag set. |  | ||||||
| See Certidude admin interface how to submit CSR-s and retrieve signed certificates. | See Certidude admin interface how to submit CSR-s and retrieve signed certificates. | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -262,26 +257,31 @@ Configure Certidude client in ``/etc/certidude/client.conf``: | |||||||
| .. code:: ini | .. code:: ini | ||||||
|  |  | ||||||
|     [ca.example.com] |     [ca.example.com] | ||||||
|     insecure = true |  | ||||||
|     trigger = interface up |     trigger = interface up | ||||||
|  |     hostname = $HOSTNAME | ||||||
|  |  | ||||||
| Configure services in ``/etc/certidude/services.conf``: | Configure services in ``/etc/certidude/services.conf``: | ||||||
|  |  | ||||||
| .. code:: bash | .. code:: bash | ||||||
|  |  | ||||||
|     [gateway.example.com] |     [OpenVPN to gateway.example.com] | ||||||
|     authority = ca.example.com |     authority = ca.example.com | ||||||
|     service = network-manager/openvpn |     service = network-manager/openvpn | ||||||
|     remote = gateway.example.com |     remote = gateway.example.com | ||||||
|  |  | ||||||
|  |     [IPSec to gateway.example.com] | ||||||
|  |     authority = ca.example.com | ||||||
|  |     service = network-manager/strongswan | ||||||
|  |     remote = gateway.example.com | ||||||
|  |  | ||||||
| To request certificate: | To request certificate: | ||||||
|  |  | ||||||
| .. code:: bash | .. code:: bash | ||||||
|  |  | ||||||
|     certidude request |     certidude enroll | ||||||
|  |  | ||||||
| The keys, signing requests, certificates and CRL-s are placed under | The keys, signing requests, certificates and CRL-s are placed under | ||||||
| /var/lib/certidude/ca.example.com/ | /etc/certidude/authority/ca.example.com/ | ||||||
|  |  | ||||||
| The VPN connection should immideately become available under network connections. | The VPN connection should immideately become available under network connections. | ||||||
|  |  | ||||||
| @@ -293,10 +293,8 @@ To use dependencies from pip: | |||||||
|  |  | ||||||
| .. code:: bash | .. code:: bash | ||||||
|  |  | ||||||
|     apt install \ |     apt install build-essential python-dev cython libffi-dev libssl-dev \ | ||||||
|         build-essential python-dev cython libffi-dev libssl-dev libkrb5-dev \ |         libkrb5-dev ldap-utils krb5-user libsasl2-modules-gssapi-mit \ | ||||||
|         ldap-utils krb5-user \ |  | ||||||
|         libsasl2-modules-gssapi-mit \ |  | ||||||
|         libsasl2-dev libldap2-dev |         libsasl2-dev libldap2-dev | ||||||
|  |  | ||||||
| Clone the repository: | Clone the repository: | ||||||
| @@ -324,7 +322,7 @@ To run tests and measure code coverage grab a clean VM or container: | |||||||
|  |  | ||||||
|     pip3 install codecov pytest-cov |     pip3 install codecov pytest-cov | ||||||
|     rm .coverage* |     rm .coverage* | ||||||
|     TRAVIS=1 coverage run --parallel-mode --source certidude -m py.test tests |     COVERAGE_FILE=/tmp/.coverage    TRAVIS=1 coverage run --parallel-mode --source certidude -m py.test tests --capture=sys | ||||||
|     coverage combine |     coverage combine | ||||||
|     coverage report |     coverage report | ||||||
|  |  | ||||||
| @@ -335,23 +333,34 @@ To uninstall: | |||||||
|     pip3 uninstall certidude |     pip3 uninstall certidude | ||||||
|  |  | ||||||
|  |  | ||||||
| Certificate attributes | Offline install | ||||||
| ---------------------- | --------------- | ||||||
|  |  | ||||||
| Certificates have a lot of fields that can be filled in. | To set up certificate authority in an isolated environment use a | ||||||
| In any case country, state, locality, organization, organizational unit are not filled in | vanilla Ubuntu 16.04 or container to collect the artifacts: | ||||||
| as this information will already exist in AD and duplicating it in the certificate management |  | ||||||
| doesn't make sense. Additionally the information will get out of sync if |  | ||||||
| attributes are changed in AD but certificates won't be updated. |  | ||||||
|  |  | ||||||
| If machine is enrolled, eg by running ``certidude request`` as root on Ubuntu/Fedora/Mac OS X: | .. code:: bash | ||||||
|  |  | ||||||
| * If Kerberos credentials are presented machine can be automatically enrolled depending on the ``machine enrollment`` setting |     add-apt-repository -y ppa:nginx/stable | ||||||
| * Common name is set to short ``hostname`` |     apt-get update -q | ||||||
| * It is tricky to determine user who is triggering the action so given name, surname and e-mail attributes are not filled in |     rm -fv /var/cache/apt/archives/*.deb /var/cache/certidude/wheels/*.whl | ||||||
|  |     apt install --download-only python3-markdown python3-pyxattr python3-jinja2 python3-cffi software-properties-common libnginx-mod-nchan nginx-full | ||||||
|  |     pip3 wheel --wheel-dir=/var/cache/certidude/wheels -r requirements.txt | ||||||
|  |     pip3 wheel --wheel-dir=/var/cache/certidude/wheels falcon humanize ipaddress simplepam user-agents python-ldap gssapi | ||||||
|  |     pip3 wheel --wheel-dir=/var/cache/certidude/wheels . | ||||||
|  |     tar -cf certidude-assets.tar /var/lib/certidude/assets/ /var/cache/apt/archives/ /var/cache/certidude/wheels | ||||||
|  |  | ||||||
| If user enrolls, eg by clicking generate bundle button in the web interface: | Transfer certidude-artifacts.tar to the target machine and execute: | ||||||
|  |  | ||||||
| * Common name is either set to ``username`` or ``username@device-identifier`` depending on the ``user enrollment`` setting | .. code:: bash | ||||||
| * Given name and surname are not filled in because Unicode characters cause issues in OpenVPN Connect app |  | ||||||
| * E-mail is not filled in because it might change in AD |     rm -fv /var/cache/apt/archives/*.deb /var/cache/certidude/wheels/*.whl | ||||||
|  |     tar -xvf certidude-artifacts.tar -C / | ||||||
|  |     dpkg -i /var/cache/apt/archives/*.deb | ||||||
|  |     pip3 install  --use-wheel --no-index --find-links /var/cache/certidude/wheels/*.whl | ||||||
|  |  | ||||||
|  | Proceed to bootstrap authority without installing packages or assembling assets: | ||||||
|  |  | ||||||
|  |     certidude setup authority  --skip-packages --skip-assets [--elliptic-curve] [--organization "Mycorp LLC"] | ||||||
|  |  | ||||||
|  | Note it's highly recommended to enable nginx PPA in the target machine | ||||||
|   | |||||||
| @@ -53,17 +53,15 @@ with open(config.AUTHORITY_PRIVATE_KEY_PATH, "rb") as fh: | |||||||
| def self_enroll(skip_notify=False): | def self_enroll(skip_notify=False): | ||||||
|     assert os.getuid() == 0 and os.getgid() == 0, "Can self-enroll only as root" |     assert os.getuid() == 0 and os.getgid() == 0, "Can self-enroll only as root" | ||||||
|  |  | ||||||
|     from certidude import const |     from certidude import const, config | ||||||
|     common_name = const.FQDN |     common_name = const.FQDN | ||||||
|     directory = os.path.join("/var/lib/certidude", const.FQDN) |  | ||||||
|     self_key_path = os.path.join(directory, "self_key.pem") |  | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         path, buf, cert, signed, expires = get_signed(common_name) |         path, buf, cert, signed, expires = get_signed(common_name) | ||||||
|         self_public_key = asymmetric.load_public_key(path) |         self_public_key = asymmetric.load_public_key(path) | ||||||
|         private_key = asymmetric.load_private_key(self_key_path) |         private_key = asymmetric.load_private_key(config.SELF_KEY_PATH) | ||||||
|     except FileNotFoundError: # certificate or private key not found |     except FileNotFoundError: # certificate or private key not found | ||||||
|         with open(self_key_path, 'wb') as fh: |         with open(config.SELF_KEY_PATH, 'wb') as fh: | ||||||
|             if public_key.algorithm == "ec": |             if public_key.algorithm == "ec": | ||||||
|                 self_public_key, private_key = asymmetric.generate_pair("ec", curve=public_key.curve) |                 self_public_key, private_key = asymmetric.generate_pair("ec", curve=public_key.curve) | ||||||
|             elif public_key.algorithm == "rsa": |             elif public_key.algorithm == "rsa": | ||||||
| @@ -81,11 +79,11 @@ def self_enroll(skip_notify=False): | |||||||
|     request = builder.build(private_key) |     request = builder.build(private_key) | ||||||
|     pid = os.fork() |     pid = os.fork() | ||||||
|     if not pid: |     if not pid: | ||||||
|         from certidude import authority |         from certidude import authority, config | ||||||
|         from certidude.common import drop_privileges |         from certidude.common import drop_privileges | ||||||
|         drop_privileges() |         drop_privileges() | ||||||
|         assert os.getuid() != 0 and os.getgid() != 0 |         assert os.getuid() != 0 and os.getgid() != 0 | ||||||
|         path = os.path.join(directory, "requests", common_name + ".pem") |         path = os.path.join(config.REQUESTS_DIR, common_name + ".pem") | ||||||
|         click.echo("Writing request to %s" % path) |         click.echo("Writing request to %s" % path) | ||||||
|         with open(path, "wb") as fh: |         with open(path, "wb") as fh: | ||||||
|             fh.write(pem_armor_csr(request)) # Write CSR with certidude permissions |             fh.write(pem_armor_csr(request)) # Write CSR with certidude permissions | ||||||
| @@ -93,10 +91,7 @@ def self_enroll(skip_notify=False): | |||||||
|         sys.exit(0) |         sys.exit(0) | ||||||
|     else: |     else: | ||||||
|         os.waitpid(pid, 0) |         os.waitpid(pid, 0) | ||||||
|         if os.path.exists("/etc/systemd"): |         os.system("systemctl reload nginx") | ||||||
|             os.system("systemctl reload nginx") |  | ||||||
|         else: |  | ||||||
|             os.system("service nginx reload") |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def get_request(common_name): | def get_request(common_name): | ||||||
|   | |||||||
							
								
								
									
										125
									
								
								certidude/cli.py
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								certidude/cli.py
									
									
									
									
									
								
							| @@ -1001,12 +1001,14 @@ def certidude_setup_openvpn_networkmanager(authority, remote, common_name, **pat | |||||||
| @click.option("--organization", "-o", default=None, help="Company or organization name") | @click.option("--organization", "-o", default=None, help="Company or organization name") | ||||||
| @click.option("--organizational-unit", "-ou", default="Certificate Authority") | @click.option("--organizational-unit", "-ou", default="Certificate Authority") | ||||||
| @click.option("--push-server", help="Push server, by default http://%s" % const.FQDN) | @click.option("--push-server", help="Push server, by default http://%s" % const.FQDN) | ||||||
| @click.option("--directory", help="Directory for authority files") | @click.option("--directory", default="/var/lib/certidude", help="Directory for authority files") | ||||||
| @click.option("--outbox", default="smtp://smtp.%s" % const.DOMAIN, help="SMTP server, smtp://smtp.%s by default" % const.DOMAIN) | @click.option("--outbox", default="smtp://smtp.%s" % const.DOMAIN, help="SMTP server, smtp://smtp.%s by default" % const.DOMAIN) | ||||||
|  | @click.option("--skip-assets", is_flag=True, help="Don't attempt to assemble JS/CSS/font assets") | ||||||
| @click.option("--skip-packages", is_flag=True, help="Don't attempt to install apt/pip/npm packages") | @click.option("--skip-packages", is_flag=True, help="Don't attempt to install 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") | ||||||
| @fqdn_required | @fqdn_required | ||||||
| def certidude_setup_authority(username, kerberos_keytab, nginx_config, organization, organizational_unit, common_name, directory, authority_lifetime, push_server, outbox, title, skip_packages, elliptic_curve): | def certidude_setup_authority(username, kerberos_keytab, nginx_config, organization, organizational_unit, common_name, directory, authority_lifetime, push_server, outbox, title, skip_assets, skip_packages, elliptic_curve, subordinate): | ||||||
|     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" | ||||||
|  |  | ||||||
| @@ -1052,8 +1054,6 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, organizat | |||||||
|     template_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates", "profile") |     template_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates", "profile") | ||||||
|     click.echo("Using templates from %s" % template_path) |     click.echo("Using templates from %s" % template_path) | ||||||
|  |  | ||||||
|     if not directory: |  | ||||||
|         directory = os.path.join("/var/lib/certidude", common_name) |  | ||||||
|     click.echo("Placing authority files in %s" % directory) |     click.echo("Placing authority files in %s" % directory) | ||||||
|  |  | ||||||
|     certificate_url = "http://%s/api/certificate/" % common_name |     certificate_url = "http://%s/api/certificate/" % common_name | ||||||
| @@ -1065,8 +1065,11 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, organizat | |||||||
|     # Expand variables |     # Expand variables | ||||||
|     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_cert = os.path.join(directory, "ca_cert.pem") |     ca_cert = os.path.join(directory, "ca_cert.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("Certidude at %s" % common_name, common_name, o=organization, ou=organizational_unit) | ||||||
|  |  | ||||||
|     # Builder variables |     # Builder variables | ||||||
|     dhgroup = "ecp384" if elliptic_curve else "modp2048" |     dhgroup = "ecp384" if elliptic_curve else "modp2048" | ||||||
| @@ -1164,35 +1167,38 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, organizat | |||||||
|             click.echo("Installing JavaScript packages: %s" % cmd) |             click.echo("Installing JavaScript packages: %s" % cmd) | ||||||
|             if os.system(cmd): sys.exit(230) |             if os.system(cmd): sys.exit(230) | ||||||
|  |  | ||||||
|         # Copy fonts |         if skip_assets: | ||||||
|         click.echo("Copying fonts...") |             click.echo("Not attempting to assemble assets as requested...") | ||||||
|         if os.system("rsync -avq /usr/local/lib/node_modules/font-awesome/fonts/ %s/fonts/" % assets_dir): sys.exit(229) |         else: | ||||||
|  |             # Copy fonts | ||||||
|  |             click.echo("Copying fonts...") | ||||||
|  |             if os.system("rsync -avq /usr/local/lib/node_modules/font-awesome/fonts/ %s/fonts/" % assets_dir): sys.exit(229) | ||||||
|  |  | ||||||
|         # Compile nunjucks templates |             # Compile nunjucks templates | ||||||
|         cmd = 'nunjucks-precompile --include ".html$" --include ".ps1$" --include ".sh$" --include ".svg" %s > %s.part' % (static_path, bundle_js) |             cmd = 'nunjucks-precompile --include ".html$" --include ".ps1$" --include ".sh$" --include ".svg" %s > %s.part' % (static_path, bundle_js) | ||||||
|         click.echo("Compiling templates: %s" % cmd) |             click.echo("Compiling templates: %s" % cmd) | ||||||
|         if os.system(cmd): sys.exit(228) |             if os.system(cmd): sys.exit(228) | ||||||
|  |  | ||||||
|         # Assemble bundle.js |             # Assemble bundle.js | ||||||
|         click.echo("Assembling %s" % bundle_js) |             click.echo("Assembling %s" % bundle_js) | ||||||
|         with open(bundle_js + ".part", "a") as fh: |             with open(bundle_js + ".part", "a") as fh: | ||||||
|             for pkg in "qrcode-svg/dist/qrcode.min.js", "jquery/dist/jquery.min.js", "timeago/*.js", "nunjucks/browser/nunjucks-slim.min.js", "tether/dist/js/*.min.js", "bootstrap/dist/js/*.min.js": |                 for pkg in "qrcode-svg/dist/qrcode.min.js", "jquery/dist/jquery.min.js", "timeago/*.js", "nunjucks/browser/nunjucks-slim.min.js", "tether/dist/js/*.min.js", "bootstrap/dist/js/*.min.js": | ||||||
|                 for j in glob(os.path.join("/usr/local/lib/node_modules", pkg)): |                     for j in glob(os.path.join("/usr/local/lib/node_modules", pkg)): | ||||||
|                     click.echo("- Merging: %s" % j) |                         click.echo("- Merging: %s" % j) | ||||||
|                     with open(j) as ih: |                         with open(j) as ih: | ||||||
|                         fh.write(ih.read()) |                             fh.write(ih.read()) | ||||||
|  |  | ||||||
|         # Assemble bundle.css |             # Assemble bundle.css | ||||||
|         click.echo("Assembling %s" % bundle_css) |             click.echo("Assembling %s" % bundle_css) | ||||||
|         with open(bundle_css + ".part", "w") as fh: |             with open(bundle_css + ".part", "w") as fh: | ||||||
|             for pkg in "tether/dist/css/*.min.css", "bootstrap/dist/css/*.min.*css", "font-awesome/css/font-awesome.min.css": |                 for pkg in "tether/dist/css/*.min.css", "bootstrap/dist/css/*.min.*css", "font-awesome/css/font-awesome.min.css": | ||||||
|                 for j in glob(os.path.join("/usr/local/lib/node_modules", pkg)): |                     for j in glob(os.path.join("/usr/local/lib/node_modules", pkg)): | ||||||
|                     click.echo("- Merging: %s" % j) |                         click.echo("- Merging: %s" % j) | ||||||
|                     with open(j) as ih: |                         with open(j) as ih: | ||||||
|                         fh.write(ih.read()) |                             fh.write(ih.read()) | ||||||
|  |  | ||||||
|         os.rename(bundle_css + ".part", bundle_css) |             os.rename(bundle_css + ".part", bundle_css) | ||||||
|         os.rename(bundle_js + ".part", bundle_js) |             os.rename(bundle_js + ".part", bundle_js) | ||||||
|  |  | ||||||
|         assert os.getuid() == 0 and os.getgid() == 0 |         assert os.getuid() == 0 and os.getgid() == 0 | ||||||
|         _, _, uid, gid, gecos, root, shell = pwd.getpwnam("certidude") |         _, _, uid, gid, gecos, root, shell = pwd.getpwnam("certidude") | ||||||
| @@ -1203,7 +1209,8 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, organizat | |||||||
|             click.echo("Creating %s" % const.CONFIG_DIR) |             click.echo("Creating %s" % const.CONFIG_DIR) | ||||||
|             os.makedirs(const.CONFIG_DIR) |             os.makedirs(const.CONFIG_DIR) | ||||||
|  |  | ||||||
|         os.umask(0o137) # 640 |         os.umask(0o177) # 600 | ||||||
|  |  | ||||||
|         if os.path.exists(const.SERVER_CONFIG_PATH): |         if os.path.exists(const.SERVER_CONFIG_PATH): | ||||||
|             click.echo("Configuration file %s already exists, remove to regenerate" % const.SERVER_CONFIG_PATH) |             click.echo("Configuration file %s already exists, remove to regenerate" % const.SERVER_CONFIG_PATH) | ||||||
|         else: |         else: | ||||||
| @@ -1250,7 +1257,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, organizat | |||||||
|                 pass |                 pass | ||||||
|  |  | ||||||
|         # Generate and sign CA key |         # Generate and sign CA key | ||||||
|         if not os.path.exists(ca_key): |         if not os.path.exists(ca_key) or subordinate and not os.path.exists(ca_req): | ||||||
|             if elliptic_curve: |             if elliptic_curve: | ||||||
|                 click.echo("Generating %s EC key for CA ..." % const.CURVE_NAME) |                 click.echo("Generating %s EC key for CA ..." % const.CURVE_NAME) | ||||||
|                 public_key, private_key = asymmetric.generate_pair("ec", curve=const.CURVE_NAME) |                 public_key, private_key = asymmetric.generate_pair("ec", curve=const.CURVE_NAME) | ||||||
| @@ -1258,12 +1265,38 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, organizat | |||||||
|                 click.echo("Generating %d-bit RSA key for CA ..." % const.KEY_SIZE) |                 click.echo("Generating %d-bit RSA key for CA ..." % const.KEY_SIZE) | ||||||
|                 public_key, private_key = asymmetric.generate_pair("rsa", bit_size=const.KEY_SIZE) |                 public_key, private_key = asymmetric.generate_pair("rsa", bit_size=const.KEY_SIZE) | ||||||
|  |  | ||||||
|  |             # Set permission bits to 600 | ||||||
|  |             os.umask(0o177) | ||||||
|  |             with open(ca_key, 'wb') as f: | ||||||
|  |                 f.write(asymmetric.dump_private_key(private_key, None)) | ||||||
|  |  | ||||||
|  |             if subordinate: | ||||||
|  |                 builder = CSRBuilder(distinguished_name, public_key) | ||||||
|  |                 request = builder.build(private_key) | ||||||
|  |                 with open(ca_req + ".part", 'wb') as f: | ||||||
|  |                     f.write(pem_armor_csr(request)) | ||||||
|  |                 os.rename(ca_req + ".part", ca_req) | ||||||
|  |  | ||||||
|  |         if not os.path.exists(ca_cert): | ||||||
|  |             if subordinate: | ||||||
|  |                 click.echo("Request has been written to %s" % ca_req) | ||||||
|  |                 click.echo() | ||||||
|  |                 click.echo(open(ca_req).read()) | ||||||
|  |                 click.echo() | ||||||
|  |                 click.echo("Get it signed and insert signed certificate into %s" % ca_cert) | ||||||
|  |                 click.echo() | ||||||
|  |                 click.echo("  cat > %s" % ca_cert) | ||||||
|  |                 click.echo() | ||||||
|  |                 click.echo("Paste contents and press Ctrl-D, adjust permissions:") | ||||||
|  |                 click.echo() | ||||||
|  |                 click.echo("  chown root:root %s" % ca_cert) | ||||||
|  |                 click.echo("  chmod 0644 %s" % ca_cert) | ||||||
|  |                 click.echo() | ||||||
|  |                 click.echo("To finish setup procedure run 'certidude setup authority' again") | ||||||
|  |                 sys.exit(1) | ||||||
|  |  | ||||||
|             # https://technet.microsoft.com/en-us/library/aa998840(v=exchg.141).aspx |             # https://technet.microsoft.com/en-us/library/aa998840(v=exchg.141).aspx | ||||||
|             builder = CertificateBuilder( |             builder = CertificateBuilder(distinguished_name, public_key) | ||||||
|                 cn_to_dn("Certidude at %s" % common_name, common_name, |  | ||||||
|                     o=organization, ou=organizational_unit), |  | ||||||
|                 public_key |  | ||||||
|             ) |  | ||||||
|             builder.self_signed = True |             builder.self_signed = True | ||||||
|             builder.ca = True |             builder.ca = True | ||||||
|             builder.serial_number = random.randint( |             builder.serial_number = random.randint( | ||||||
| @@ -1280,22 +1313,20 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, organizat | |||||||
|             with open(ca_cert, 'wb') as f: |             with open(ca_cert, 'wb') as f: | ||||||
|                 f.write(pem_armor_certificate(certificate)) |                 f.write(pem_armor_certificate(certificate)) | ||||||
|  |  | ||||||
|             # Set permission bits to 600 |  | ||||||
|             os.umask(0o177) |  | ||||||
|             with open(ca_key, 'wb') as f: |  | ||||||
|                 f.write(asymmetric.dump_private_key(private_key, None)) |  | ||||||
|  |  | ||||||
|         sys.exit(0) # stop this fork here |         sys.exit(0) # stop this fork here | ||||||
|  |  | ||||||
|         assert os.stat(sqlite_path).st_mode == 0o100640 |  | ||||||
|         assert os.stat(ca_cert).st_mode == 0o100640 |  | ||||||
|         assert os.stat(ca_key).st_mode == 0o100600 |  | ||||||
|         assert os.stat("/etc/nginx/sites-available/certidude.conf").st_mode == 0o100640 |  | ||||||
|     else: |     else: | ||||||
|         os.waitpid(bootstrap_pid, 0) |         _, exitcode = os.waitpid(bootstrap_pid, 0) | ||||||
|  |         if exitcode: | ||||||
|  |             return 0 | ||||||
|         from certidude import authority |         from certidude import authority | ||||||
|         authority.self_enroll(skip_notify=True) |         authority.self_enroll(skip_notify=True) | ||||||
|         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(ca_cert).st_mode == 0o100640 | ||||||
|  |         assert os.stat(ca_key).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 | ||||||
|  |  | ||||||
|         click.echo("Enabling and starting Certidude backend") |         click.echo("Enabling and starting Certidude backend") | ||||||
|         os.system("systemctl enable certidude") |         os.system("systemctl enable certidude") | ||||||
|         os.system("systemctl restart certidude") |         os.system("systemctl restart certidude") | ||||||
|   | |||||||
| @@ -50,6 +50,7 @@ KERBEROS_SUBNETS = set([ipaddress.ip_network(j) for j in | |||||||
| AUTHORITY_DIR = "/var/lib/certidude" | AUTHORITY_DIR = "/var/lib/certidude" | ||||||
| AUTHORITY_PRIVATE_KEY_PATH = cp.get("authority", "private key path") | AUTHORITY_PRIVATE_KEY_PATH = cp.get("authority", "private key path") | ||||||
| AUTHORITY_CERTIFICATE_PATH = cp.get("authority", "certificate path") | AUTHORITY_CERTIFICATE_PATH = cp.get("authority", "certificate path") | ||||||
|  | SELF_KEY_PATH = cp.get("authority", "self key path") | ||||||
| REQUESTS_DIR = cp.get("authority", "requests dir") | REQUESTS_DIR = cp.get("authority", "requests dir") | ||||||
| SIGNED_DIR = cp.get("authority", "signed dir") | SIGNED_DIR = cp.get("authority", "signed dir") | ||||||
| SIGNED_BY_SERIAL_DIR = os.path.join(SIGNED_DIR, "by-serial") | SIGNED_BY_SERIAL_DIR = os.path.join(SIGNED_DIR, "by-serial") | ||||||
|   | |||||||
| @@ -23,8 +23,8 @@ send_timeout 600; | |||||||
| nchan_message_buffer_length 0; | nchan_message_buffer_length 0; | ||||||
|  |  | ||||||
| # To use CA-s own certificate for frontend and mutually authenticated connections | # To use CA-s own certificate for frontend and mutually authenticated connections | ||||||
| ssl_certificate /var/lib/certidude/{{ common_name }}/signed/{{ common_name }}.pem; | ssl_certificate {{ directory }}/signed/{{ common_name }}.pem; | ||||||
| ssl_certificate_key /var/lib/certidude/{{common_name}}/self_key.pem; | ssl_certificate_key {{ directory }}/self_key.pem; | ||||||
|  |  | ||||||
| server { | server { | ||||||
|     # Section for serving insecure HTTP, note that this is suitable for |     # Section for serving insecure HTTP, note that this is suitable for | ||||||
| @@ -138,7 +138,7 @@ server { | |||||||
|     # 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 /var/lib/certidude/{{ common_name }}/ca_cert.pem; |     ssl_client_certificate {{ directory }}/ca_cert.pem; | ||||||
|  |  | ||||||
|     # Proxy pass to backend |     # Proxy pass to backend | ||||||
|     location /api/ { |     location /api/ { | ||||||
|   | |||||||
| @@ -25,9 +25,9 @@ kerberos realm = EXAMPLE.LAN | |||||||
|  |  | ||||||
| {% if domain %} | {% if domain %} | ||||||
| # LDAP URI derived from /etc/samba/smb.conf | # LDAP URI derived from /etc/samba/smb.conf | ||||||
| ldap uri = ldap://dc1.{{ domain }} | ldap uri = ldaps://dc1.{{ domain }} | ||||||
| {% else %} | {% else %} | ||||||
| # LDAP URI | # Placeholder LDAP URI | ||||||
| ldap uri = ldaps://dc1.example.lan | ldap uri = ldaps://dc1.example.lan | ||||||
| {% endif %} | {% endif %} | ||||||
|  |  | ||||||
| @@ -223,9 +223,14 @@ request submission allowed = false | |||||||
| ;user enrollment = single allowed | ;user enrollment = single allowed | ||||||
| user enrollment = multiple allowed | user enrollment = multiple allowed | ||||||
|  |  | ||||||
|  | # Certificate authority keypair | ||||||
| private key path = {{ ca_key }} | private key path = {{ ca_key }} | ||||||
| certificate path = {{ ca_cert }} | certificate path = {{ ca_cert }} | ||||||
|  |  | ||||||
|  | # Private key used by nginx frontend | ||||||
|  | self key path = {{ self_key }} | ||||||
|  |  | ||||||
|  | # Directories for requests, signed, revoked and expired certificates | ||||||
| requests dir = {{ directory }}/requests/ | requests dir = {{ directory }}/requests/ | ||||||
| signed dir = {{ directory }}/signed/ | signed dir = {{ directory }}/signed/ | ||||||
| revoked dir = {{ directory }}/revoked/ | revoked dir = {{ directory }}/revoked/ | ||||||
|   | |||||||
| @@ -96,8 +96,8 @@ def clean_server(): | |||||||
|                 pass |                 pass | ||||||
|  |  | ||||||
|  |  | ||||||
|     if os.path.exists("/var/lib/certidude/ca.example.lan"): |     if os.path.exists("/var/lib/certidude"): | ||||||
|         shutil.rmtree("/var/lib/certidude/ca.example.lan") |         shutil.rmtree("/var/lib/certidude") | ||||||
|     if os.path.exists("/run/certidude"): |     if os.path.exists("/run/certidude"): | ||||||
|         shutil.rmtree("/run/certidude") |         shutil.rmtree("/run/certidude") | ||||||
|  |  | ||||||
| @@ -230,13 +230,13 @@ def test_cli_setup_authority(): | |||||||
|     assert authority.public_key.algorithm == "ec" |     assert authority.public_key.algorithm == "ec" | ||||||
|  |  | ||||||
|     # Generate garbage |     # Generate garbage | ||||||
|     with open("/var/lib/certidude/ca.example.lan/bla", "w") as fh: |     with open("/var/lib/certidude/bla", "w") as fh: | ||||||
|         pass |         pass | ||||||
|     with open("/var/lib/certidude/ca.example.lan/requests/bla", "w") as fh: |     with open("/var/lib/certidude/requests/bla", "w") as fh: | ||||||
|         pass |         pass | ||||||
|     with open("/var/lib/certidude/ca.example.lan/signed/bla", "w") as fh: |     with open("/var/lib/certidude/signed/bla", "w") as fh: | ||||||
|         pass |         pass | ||||||
|     with open("/var/lib/certidude/ca.example.lan/revoked/bla", "w") as fh: |     with open("/var/lib/certidude/revoked/bla", "w") as fh: | ||||||
|         pass |         pass | ||||||
|  |  | ||||||
|     # Start server before any signing operations are performed |     # Start server before any signing operations are performed | ||||||
| @@ -255,7 +255,7 @@ def test_cli_setup_authority(): | |||||||
|  |  | ||||||
|  |  | ||||||
|     # Test CA certificate fetch |     # Test CA certificate fetch | ||||||
|     buf = open("/var/lib/certidude/ca.example.lan/ca_cert.pem").read() |     buf = open("/var/lib/certidude/ca_cert.pem").read() | ||||||
|     r = requests.get("http://ca.example.lan/api/certificate") |     r = requests.get("http://ca.example.lan/api/certificate") | ||||||
|     assert r.status_code == 200 |     assert r.status_code == 200 | ||||||
|     assert r.headers.get('content-type') == "application/x-x509-ca-cert" |     assert r.headers.get('content-type') == "application/x-x509-ca-cert" | ||||||
| @@ -308,7 +308,7 @@ def test_cli_setup_authority(): | |||||||
|         headers={"content-type":"application/pkcs10"}) |         headers={"content-type":"application/pkcs10"}) | ||||||
|     assert r.status_code == 202 # success |     assert r.status_code == 202 # success | ||||||
|     assert "Stored request " in inbox.pop(), inbox |     assert "Stored request " in inbox.pop(), inbox | ||||||
|     assert os.path.exists("/var/lib/certidude/ca.example.lan/requests/test.pem") |     assert os.path.exists("/var/lib/certidude/requests/test.pem") | ||||||
|  |  | ||||||
|     # Test request deletion |     # Test request deletion | ||||||
|     r = client().simulate_delete("/api/request/test/") |     r = client().simulate_delete("/api/request/test/") | ||||||
| @@ -319,7 +319,7 @@ def test_cli_setup_authority(): | |||||||
|     r = client().simulate_delete("/api/request/test/", |     r = client().simulate_delete("/api/request/test/", | ||||||
|         headers={"User-Agent":UA_FEDORA_FIREFOX, "Authorization":admintoken}) |         headers={"User-Agent":UA_FEDORA_FIREFOX, "Authorization":admintoken}) | ||||||
|     assert r.status_code == 403, r.text # CSRF prevented |     assert r.status_code == 403, r.text # CSRF prevented | ||||||
|     assert os.path.exists("/var/lib/certidude/ca.example.lan/requests/test.pem") |     assert os.path.exists("/var/lib/certidude/requests/test.pem") | ||||||
|     r = client().simulate_delete("/api/request/test/", |     r = client().simulate_delete("/api/request/test/", | ||||||
|         headers={"Authorization":admintoken}) |         headers={"Authorization":admintoken}) | ||||||
|     assert r.status_code == 200, r.text |     assert r.status_code == 200, r.text | ||||||
| @@ -507,19 +507,19 @@ def test_cli_setup_authority(): | |||||||
|  |  | ||||||
|     r = client().simulate_post("/api/lease/", |     r = client().simulate_post("/api/lease/", | ||||||
|         query_string = "client=test&inner_address=127.0.0.1&outer_address=8.8.8.8", |         query_string = "client=test&inner_address=127.0.0.1&outer_address=8.8.8.8", | ||||||
|         headers={"X-SSL-CERT":open("/var/lib/certidude/ca.example.lan/signed/ca.example.lan.pem").read() }) |         headers={"X-SSL-CERT":open("/var/lib/certidude/signed/ca.example.lan.pem").read() }) | ||||||
|     assert r.status_code == 200, r.text # lease update ok |     assert r.status_code == 200, r.text # lease update ok | ||||||
|  |  | ||||||
|     # Attempt to fetch and execute default.sh script |     # Attempt to fetch and execute default.sh script | ||||||
|     from xattr import listxattr, getxattr |     from xattr import listxattr, getxattr | ||||||
|     assert not [j for j in listxattr("/var/lib/certidude/ca.example.lan/signed/test.pem") if j.startswith(b"user.machine.")] |     assert not [j for j in listxattr("/var/lib/certidude/signed/test.pem") if j.startswith(b"user.machine.")] | ||||||
|     #os.system("curl http://ca.example.lan/api/signed/test/script | bash") |     #os.system("curl http://ca.example.lan/api/signed/test/script | bash") | ||||||
|     r = client().simulate_post("/api/signed/test/attr", body="cpu=i5&mem=512M&dist=Ubunt", |     r = client().simulate_post("/api/signed/test/attr", body="cpu=i5&mem=512M&dist=Ubunt", | ||||||
|         headers={"content-type": "application/x-www-form-urlencoded"}) |         headers={"content-type": "application/x-www-form-urlencoded"}) | ||||||
|     assert r.status_code == 200, r.text |     assert r.status_code == 200, r.text | ||||||
|     assert getxattr("/var/lib/certidude/ca.example.lan/signed/test.pem", "user.machine.cpu") == b"i5" |     assert getxattr("/var/lib/certidude/signed/test.pem", "user.machine.cpu") == b"i5" | ||||||
|     assert getxattr("/var/lib/certidude/ca.example.lan/signed/test.pem", "user.machine.mem") == b"512M" |     assert getxattr("/var/lib/certidude/signed/test.pem", "user.machine.mem") == b"512M" | ||||||
|     assert getxattr("/var/lib/certidude/ca.example.lan/signed/test.pem", "user.machine.dist") == b"Ubunt" |     assert getxattr("/var/lib/certidude/signed/test.pem", "user.machine.dist") == b"Ubunt" | ||||||
|  |  | ||||||
|     # 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/") | ||||||
| @@ -572,11 +572,11 @@ def test_cli_setup_authority(): | |||||||
|     # Test lease update |     # Test lease update | ||||||
|     r = client().simulate_post("/api/lease/", |     r = client().simulate_post("/api/lease/", | ||||||
|         query_string = "client=test&inner_address=127.0.0.1&outer_address=8.8.8.8&serial=0", |         query_string = "client=test&inner_address=127.0.0.1&outer_address=8.8.8.8&serial=0", | ||||||
|         headers={"X-SSL-CERT":open("/var/lib/certidude/ca.example.lan/signed/ca.example.lan.pem").read() }) |         headers={"X-SSL-CERT":open("/var/lib/certidude/signed/ca.example.lan.pem").read() }) | ||||||
|     assert r.status_code == 403, r.text # invalid serial number supplied |     assert r.status_code == 403, r.text # invalid serial number supplied | ||||||
|     r = client().simulate_post("/api/lease/", |     r = client().simulate_post("/api/lease/", | ||||||
|         query_string = "client=test&inner_address=1.2.3.4&outer_address=8.8.8.8", |         query_string = "client=test&inner_address=1.2.3.4&outer_address=8.8.8.8", | ||||||
|         headers={"X-SSL-CERT":open("/var/lib/certidude/ca.example.lan/signed/ca.example.lan.pem").read() }) |         headers={"X-SSL-CERT":open("/var/lib/certidude/signed/ca.example.lan.pem").read() }) | ||||||
|     assert r.status_code == 200, r.text # lease update ok |     assert r.status_code == 200, r.text # lease update ok | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -717,11 +717,11 @@ def test_cli_setup_authority(): | |||||||
|     assert not result.exception, result.output |     assert not result.exception, result.output | ||||||
|     assert "(autosign not requested)" in result.output, result.output |     assert "(autosign not requested)" in result.output, result.output | ||||||
|     assert not os.path.exists("/run/certidude/ca.example.lan.pid"), result.output |     assert not os.path.exists("/run/certidude/ca.example.lan.pid"), result.output | ||||||
|     assert not os.path.exists("/var/lib/certidude/ca.example.lan/signed/vpn.example.lan.pem") |     assert not os.path.exists("/var/lib/certidude/signed/vpn.example.lan.pem") | ||||||
|  |  | ||||||
|     child_pid = os.fork() |     child_pid = os.fork() | ||||||
|     if not child_pid: |     if not child_pid: | ||||||
|         assert not os.path.exists("/var/lib/certidude/ca.example.lan/signed/vpn.example.lan.pem") |         assert not os.path.exists("/var/lib/certidude/signed/vpn.example.lan.pem") | ||||||
|         result = runner.invoke(cli, ["sign", "vpn.example.lan", "--profile", "srv"]) |         result = runner.invoke(cli, ["sign", "vpn.example.lan", "--profile", "srv"]) | ||||||
|         assert not result.exception, result.output |         assert not result.exception, result.output | ||||||
|         assert "overwrit" not in result.output, result.output |         assert "overwrit" not in result.output, result.output | ||||||
| @@ -912,20 +912,20 @@ def test_cli_setup_authority(): | |||||||
|     # Setup gateway |     # Setup gateway | ||||||
|  |  | ||||||
|     clean_client() |     clean_client() | ||||||
|     assert not os.path.exists("/var/lib/certidude/ca.example.lan/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, ['setup', '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/ca.example.lan/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, ['setup', '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/ca.example.lan/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, ['setup', '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/ca.example.lan/signed/ipsec.example.lan.pem") |     assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") | ||||||
|  |  | ||||||
|     with open("/etc/certidude/client.conf", "a") as fh: |     with open("/etc/certidude/client.conf", "a") as fh: | ||||||
|         fh.write("autosign = false\n") |         fh.write("autosign = false\n") | ||||||
| @@ -934,11 +934,11 @@ def test_cli_setup_authority(): | |||||||
|     assert not result.exception, result.output |     assert not result.exception, result.output | ||||||
|     assert "(autosign not requested)" in result.output, result.output |     assert "(autosign not requested)" in result.output, result.output | ||||||
|     assert not os.path.exists("/run/certidude/ca.example.lan.pid"), result.output |     assert not os.path.exists("/run/certidude/ca.example.lan.pid"), result.output | ||||||
|     assert not os.path.exists("/var/lib/certidude/ca.example.lan/signed/ipsec.example.lan.pem") |     assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") | ||||||
|  |  | ||||||
|     child_pid = os.fork() |     child_pid = os.fork() | ||||||
|     if not child_pid: |     if not child_pid: | ||||||
|         assert not os.path.exists("/var/lib/certidude/ca.example.lan/signed/ipsec.example.lan.pem") |         assert not os.path.exists("/var/lib/certidude/signed/ipsec.example.lan.pem") | ||||||
|         result = runner.invoke(cli, ["sign", "ipsec.example.lan", "--profile", "srv"]) |         result = runner.invoke(cli, ["sign", "ipsec.example.lan", "--profile", "srv"]) | ||||||
|         assert not result.exception, result.output |         assert not result.exception, result.output | ||||||
|         assert "overwrit" not in result.output, result.output |         assert "overwrit" not in result.output, result.output | ||||||
| @@ -1024,13 +1024,13 @@ def test_cli_setup_authority(): | |||||||
|     assert r.status_code == 400 |     assert r.status_code == 400 | ||||||
|  |  | ||||||
|  |  | ||||||
|     assert os.system("openssl ocsp -issuer /var/lib/certidude/ca.example.lan/ca_cert.pem -CAfile /var/lib/certidude/ca.example.lan/ca_cert.pem -cert /var/lib/certidude/ca.example.lan/signed/roadwarrior2.pem -text -url http://ca.example.lan/api/ocsp/ -out /tmp/ocsp1.log") == 0 |     assert os.system("openssl ocsp -issuer /var/lib/certidude/ca_cert.pem -CAfile /var/lib/certidude/ca_cert.pem -cert /var/lib/certidude/signed/roadwarrior2.pem -text -url http://ca.example.lan/api/ocsp/ -out /tmp/ocsp1.log") == 0 | ||||||
|     assert os.system("openssl ocsp -issuer /var/lib/certidude/ca.example.lan/ca_cert.pem -CAfile /var/lib/certidude/ca.example.lan/ca_cert.pem -cert /var/lib/certidude/ca.example.lan/ca_cert.pem -text -url http://ca.example.lan/api/ocsp/ -out /tmp/ocsp2.log") == 0 |     assert os.system("openssl ocsp -issuer /var/lib/certidude/ca_cert.pem -CAfile /var/lib/certidude/ca_cert.pem -cert /var/lib/certidude/ca_cert.pem -text -url http://ca.example.lan/api/ocsp/ -out /tmp/ocsp2.log") == 0 | ||||||
|  |  | ||||||
|     for filename in os.listdir("/var/lib/certidude/ca.example.lan/revoked"): |     for filename in os.listdir("/var/lib/certidude/revoked"): | ||||||
|         if not filename.endswith(".pem"): |         if not filename.endswith(".pem"): | ||||||
|             continue |             continue | ||||||
|         assert os.system("openssl ocsp -issuer /var/lib/certidude/ca.example.lan/ca_cert.pem -CAfile /var/lib/certidude/ca.example.lan/ca_cert.pem -cert /var/lib/certidude/ca.example.lan/revoked/%s -text -url http://ca.example.lan/api/ocsp/ -out /tmp/ocsp3.log" % filename) == 0 |         assert os.system("openssl ocsp -issuer /var/lib/certidude/ca_cert.pem -CAfile /var/lib/certidude/ca_cert.pem -cert /var/lib/certidude/revoked/%s -text -url http://ca.example.lan/api/ocsp/ -out /tmp/ocsp3.log" % filename) == 0 | ||||||
|         break |         break | ||||||
|  |  | ||||||
|     with open("/tmp/ocsp1.log") as fh: |     with open("/tmp/ocsp1.log") as fh: | ||||||
| @@ -1108,7 +1108,7 @@ def test_cli_setup_authority(): | |||||||
|  |  | ||||||
|  |  | ||||||
|     # Bootstrap authority |     # Bootstrap authority | ||||||
|     assert not os.path.exists("/var/lib/certidude/ca.example.lan/ca_key.pem") |     assert not os.path.exists("/var/lib/certidude/ca_key.pem") | ||||||
|     assert os.system("certidude setup authority --skip-packages") == 0 |     assert os.system("certidude setup authority --skip-packages") == 0 | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user