mirror of
https://github.com/laurivosandi/certidude
synced 2024-12-22 08:15:18 +00:00
Grand unified snippets
This commit is contained in:
parent
da689ad96f
commit
2b86a5c2c7
27
README.rst
27
README.rst
@ -60,7 +60,7 @@ Features
|
||||
Common:
|
||||
|
||||
* 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.
|
||||
* PAM and Active Directory compliant authentication backends: Kerberos single sign-on, LDAP simple bind.
|
||||
* POSIX groups and Active Directory (LDAP) group membership based authorization.
|
||||
@ -74,14 +74,14 @@ Common:
|
||||
Virtual private networking:
|
||||
|
||||
* 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``.
|
||||
* StrongSwan gateway and roadwarrior integration, check out ``certidude setup strongswan server`` and ``certidude setup strongswan client``.
|
||||
* NetworkManager integration for Ubuntu and Fedora, check out ``certidude setup openvpn networkmanager`` and ``certidude setup strongswan networkmanager``.
|
||||
* OpenVPN gateway and roadwarrior integration, check out ``certidude provision openvpn server`` and ``certidude provision openvpn 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 provision openvpn networkmanager`` and ``certidude provision strongswan networkmanager``.
|
||||
|
||||
HTTPS:
|
||||
|
||||
* 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
|
||||
@ -141,7 +141,7 @@ cronjobs in ``/etc/cron.hourly/certidude`` and much more:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
certidude setup authority
|
||||
certidude provision authority
|
||||
|
||||
Tweak the configuration in ``/etc/certidude/server.conf`` until you meet your requirements,
|
||||
to apply changes run:
|
||||
@ -170,7 +170,7 @@ Python modules:
|
||||
|
||||
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.
|
||||
|
||||
Setting up Active Directory authentication
|
||||
@ -335,6 +335,17 @@ To uninstall:
|
||||
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
|
||||
---------------
|
||||
|
||||
@ -367,6 +378,6 @@ Proceed to bootstrap authority without installing packages or assembling assets:
|
||||
|
||||
.. 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
|
||||
|
@ -117,3 +117,6 @@ class OCSPResource(AuthorityHandler):
|
||||
}
|
||||
}).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
|
||||
common_name = const.FQDN
|
||||
os.umask(0o0177)
|
||||
|
||||
try:
|
||||
path, buf, cert, signed, expires = get_signed(common_name)
|
||||
|
@ -59,7 +59,7 @@ esac
|
||||
cat << EOF > $OVERLAY/etc/certidude/authority/$AUTHORITY/updown
|
||||
#!/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/"
|
||||
|
||||
case \$PLUTO_VERB in
|
||||
|
@ -96,7 +96,7 @@ fi
|
||||
|
||||
logger -t certidude -s "Request md5sum is $(md5sum -b $REQUEST_PATH)"
|
||||
|
||||
curl -f -L \
|
||||
curl --cert-status -f -L \
|
||||
-H "Content-Type: application/pkcs10" \
|
||||
--cacert $AUTHORITY_PATH \
|
||||
--data-binary @$REQUEST_PATH \
|
||||
|
@ -10,7 +10,7 @@ KEY_PATH=$DIR/host_key.pem
|
||||
|
||||
# TODO: fix Accepted 202 here
|
||||
|
||||
curl -f -L \
|
||||
curl --cert-status -f -L \
|
||||
-H "Content-Type: application/pkcs10" \
|
||||
--data-binary @$REQUEST_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")
|
||||
@fqdn_required
|
||||
@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
|
||||
apt("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']))
|
||||
@fqdn_required
|
||||
@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")
|
||||
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):
|
||||
click.echo("Configuration file %s already exists, not overwriting" % site_config.name)
|
||||
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)
|
||||
|
||||
if os.path.exists(tls_config.name):
|
||||
click.echo("Configuration file %s already exists, not overwriting" % tls_config.name)
|
||||
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()
|
||||
click.echo("Inspect configuration files, enable it and start nginx service:")
|
||||
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),
|
||||
help="OpenVPN configuration file")
|
||||
@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
|
||||
apt("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")
|
||||
@fqdn_required
|
||||
@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
|
||||
apt("strongswan")
|
||||
rpm("strongswan")
|
||||
@ -892,7 +891,7 @@ def certidude_setup_strongswan_server(authority, common_name, subnet, route, **p
|
||||
@click.argument("remote")
|
||||
@click.option("--common-name", "-cn", default=const.HOSTNAME, help="Common name, %s by default" % const.HOSTNAME)
|
||||
@setup_client()
|
||||
def certidude_setup_strongswan_client(authority, remote, common_name, **paths):
|
||||
def certidude_provision_strongswan_client(authority, remote, common_name, **paths):
|
||||
# Install dependencies
|
||||
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.option("--common-name", "-cn", default=const.HOSTNAME, help="Common name, %s by default" % const.HOSTNAME)
|
||||
@setup_client()
|
||||
def certidude_setup_strongswan_networkmanager(authority, remote, common_name, **paths):
|
||||
def certidude_provision_strongswan_networkmanager(authority, remote, common_name, **paths):
|
||||
# Install dependencies
|
||||
apt("network-manager strongswan-nm")
|
||||
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.option("--common-name", "-cn", default=const.HOSTNAME, help="Common name, %s by default" % const.HOSTNAME)
|
||||
@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")
|
||||
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.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("--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",
|
||||
@ -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("--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")
|
||||
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 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
|
||||
from jinja2 import Environment, PackageLoader
|
||||
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):
|
||||
raise click.ClickException("Failed to install JavaScript packages")
|
||||
|
||||
if not os.path.exists("/usr/bin/node"):
|
||||
os.symlink("/usr/bin/nodejs", "/usr/bin/node")
|
||||
verbose_symlink("/usr/bin/node", "/usr/bin/nodejs")
|
||||
|
||||
if packages_only:
|
||||
return
|
||||
@ -1100,7 +1113,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi
|
||||
assets_dir = os.path.join(directory, "assets")
|
||||
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")
|
||||
authority_path = 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")
|
||||
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):
|
||||
click.echo("Service principal keytab found in '%s'" % kerberos_keytab)
|
||||
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(" kinit administrator@EXAMPLE.LAN")
|
||||
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(" chown %s %s" % (username, kerberos_keytab))
|
||||
click.echo(" mv /etc/certidude/server.conf /etc/certidude/server.backup")
|
||||
click.echo(" certidude setup authority")
|
||||
click.echo(" certidude provision authority")
|
||||
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"):
|
||||
# Fetch Kerberos ticket for system account
|
||||
cp = ConfigParser()
|
||||
@ -1148,6 +1153,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi
|
||||
name = cp.get("global", "netbios name")
|
||||
base = ",".join(["dc=" + j for j in domain.split(".")])
|
||||
else:
|
||||
realm = None
|
||||
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
|
||||
@ -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")
|
||||
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")
|
||||
certidude_path = sys.argv[0]
|
||||
|
||||
click.echo("Generating: %s" % nginx_config.name)
|
||||
nginx_config.write(env.get_template("server/nginx.conf").render(vars()))
|
||||
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")
|
||||
click.echo("Symlinked %s -> /etc/nginx/sites-enabled/" % nginx_config.name)
|
||||
|
||||
def verbose_render_systemd_service(template, target, context):
|
||||
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"):
|
||||
os.unlink("/etc/nginx/sites-enabled/default")
|
||||
if os.path.exists("/etc/systemd"):
|
||||
if os.path.exists("/etc/systemd/system/certidude.service"):
|
||||
click.echo("File /etc/systemd/system/certidude.service already exists, remove to regenerate")
|
||||
else:
|
||||
with open("/etc/systemd/system/certidude.service", "w") as fh:
|
||||
fh.write(env.get_template("server/systemd.service").render(vars()))
|
||||
click.echo("File /etc/systemd/system/certidude.service created")
|
||||
os.system("systemctl daemon-reload")
|
||||
verbose_render_systemd_service("server/backend.service", "certidude-backend.service", vars())
|
||||
verbose_render_systemd_service("server/ldap-kinit.service", "certidude-ldap-kinit.service", vars())
|
||||
verbose_render_systemd_service("server/ldap-kinit.timer", "certidude-ldap-kinit.timer", vars())
|
||||
verbose_render_systemd_service("snippets/nginx-ocsp-cache.service", "certidude-ocsp-cache.service", vars())
|
||||
verbose_render_systemd_service("snippets/nginx-ocsp-cache.timer", "certidude-ocsp-cache.timer", vars())
|
||||
else:
|
||||
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")
|
||||
|
||||
# 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)
|
||||
if os.system(cmd):
|
||||
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):
|
||||
click.echo("Configuration file %s already exists, not overwriting" % tls_config.name)
|
||||
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)
|
||||
|
||||
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)
|
||||
for subdir in ("signed", "signed/by-serial", "requests", "revoked", "expired", "meta", "builder"):
|
||||
path = os.path.join(directory, subdir)
|
||||
if not os.path.exists(path):
|
||||
click.echo("Creating directory %s" % path)
|
||||
os.mkdir(path)
|
||||
else:
|
||||
click.echo("Directory already exists %s" % path)
|
||||
verbose_makedirs(path)
|
||||
assert os.stat(path).st_mode == 0o40770, path
|
||||
|
||||
# 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:
|
||||
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
|
||||
if not os.path.exists(ca_key) or subordinate and not os.path.exists(ca_req):
|
||||
if elliptic_curve:
|
||||
@ -1329,22 +1356,22 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, tls_confi
|
||||
f.write(pem_armor_csr(request))
|
||||
os.rename(ca_req + ".part", ca_req)
|
||||
|
||||
if not os.path.exists(ca_cert):
|
||||
if not os.path.exists(authority_path):
|
||||
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("Get it signed and insert signed certificate into %s" % authority_path)
|
||||
click.echo()
|
||||
click.echo(" cat > %s" % ca_cert)
|
||||
click.echo(" cat > %s" % authority_path)
|
||||
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(" chown root:root %s" % authority_path)
|
||||
click.echo(" chmod 0644 %s" % authority_path)
|
||||
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
|
||||
|
||||
# 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
|
||||
os.umask(0o137)
|
||||
with open(ca_cert, 'wb') as f:
|
||||
with open(authority_path, 'wb') as f:
|
||||
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
|
||||
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.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(authority_path).st_mode == 0o100640
|
||||
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/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()
|
||||
click.echo("Use following commands to inspect the newly created files:")
|
||||
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 verify -CAfile %s %s" % (ca_cert, ca_cert))
|
||||
click.echo(" openssl verify -CAfile %s %s" % (authority_path, authority_path))
|
||||
click.echo()
|
||||
click.echo("To inspect logs and issued tokens:")
|
||||
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()
|
||||
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 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()
|
||||
click.echo(" systemctl restart certidude")
|
||||
click.echo(" systemctl restart certidude-backend")
|
||||
click.echo(" systemctl restart nginx")
|
||||
click.echo(" systemctl start certidude-ocsp-cache.service")
|
||||
click.echo()
|
||||
return 0
|
||||
|
||||
@ -1517,8 +1560,8 @@ def certidude_revoke(common_name, reason):
|
||||
authority.revoke(common_name, reason)
|
||||
|
||||
|
||||
@click.command("hourly", help="Hourly housekeeping tasks")
|
||||
def certidude_cron_hourly():
|
||||
@click.command("kinit", help="Initialize Kerberos credential cache for LDAP")
|
||||
def certidude_housekeeping_kinit():
|
||||
from certidude import config
|
||||
|
||||
# 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")
|
||||
|
||||
|
||||
@click.command("daily", help="Daily housekeeping tasks")
|
||||
def certidude_cron_daily():
|
||||
@click.command("daily", help="Send notifications about expired certificates")
|
||||
def certidude_housekeeping_expiration():
|
||||
from certidude import authority, config, mailer
|
||||
threshold_move = datetime.utcnow() - const.CLOCK_SKEW_TOLERANCE
|
||||
threshold_notify = datetime.utcnow() + timedelta(hours=48)
|
||||
@ -1633,11 +1676,6 @@ def certidude_serve(port, listen, fork):
|
||||
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
|
||||
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("-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"))
|
||||
def certidude_setup_yubikey(authority, slot, username, pin):
|
||||
def certidude_provision_yubikey(authority, slot, username, pin):
|
||||
import requests
|
||||
cmd = "ykinfo", "-q", "-s"
|
||||
click.echo("Executing: %s" % " ".join(cmd))
|
||||
@ -1750,47 +1788,48 @@ def certidude_token_issue(subject, subject_mail):
|
||||
|
||||
|
||||
@click.group("strongswan", help="strongSwan helpers")
|
||||
def certidude_setup_strongswan(): pass
|
||||
def certidude_provision_strongswan(): pass
|
||||
|
||||
@click.group("openvpn", help="OpenVPN helpers")
|
||||
def certidude_setup_openvpn(): pass
|
||||
def certidude_provision_openvpn(): pass
|
||||
|
||||
@click.group("setup", help="Getting started section")
|
||||
def certidude_setup(): pass
|
||||
@click.group("provision", help="Getting started section")
|
||||
def certidude_provision(): pass
|
||||
|
||||
@click.group("housekeeping", help="Housekeeping tasks")
|
||||
def certidude_housekeeping(): pass
|
||||
|
||||
@click.group("token", help="Token management")
|
||||
def certidude_token(): pass
|
||||
|
||||
@click.group("cron", help="Housekeeping tasks")
|
||||
def certidude_cron(): pass
|
||||
|
||||
@click.group()
|
||||
def entry_point(): pass
|
||||
|
||||
certidude_setup_strongswan.add_command(certidude_setup_strongswan_server)
|
||||
certidude_setup_strongswan.add_command(certidude_setup_strongswan_client)
|
||||
certidude_setup_strongswan.add_command(certidude_setup_strongswan_networkmanager)
|
||||
certidude_setup_openvpn.add_command(certidude_setup_openvpn_server)
|
||||
certidude_setup_openvpn.add_command(certidude_setup_openvpn_client)
|
||||
certidude_setup_openvpn.add_command(certidude_setup_openvpn_networkmanager)
|
||||
certidude_setup.add_command(certidude_setup_authority)
|
||||
certidude_setup.add_command(certidude_setup_openvpn)
|
||||
certidude_setup.add_command(certidude_setup_strongswan)
|
||||
certidude_setup.add_command(certidude_setup_nginx)
|
||||
certidude_setup.add_command(certidude_setup_yubikey)
|
||||
|
||||
certidude_provision_strongswan.add_command(certidude_provision_strongswan_server)
|
||||
certidude_provision_strongswan.add_command(certidude_provision_strongswan_client)
|
||||
certidude_provision_strongswan.add_command(certidude_provision_strongswan_networkmanager)
|
||||
certidude_provision_openvpn.add_command(certidude_provision_openvpn_server)
|
||||
certidude_provision_openvpn.add_command(certidude_provision_openvpn_client)
|
||||
certidude_provision_openvpn.add_command(certidude_provision_openvpn_networkmanager)
|
||||
certidude_provision.add_command(certidude_provision_authority)
|
||||
certidude_provision.add_command(certidude_provision_openvpn)
|
||||
certidude_provision.add_command(certidude_provision_strongswan)
|
||||
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_purge)
|
||||
certidude_token.add_command(certidude_token_issue)
|
||||
certidude_cron.add_command(certidude_cron_hourly)
|
||||
certidude_cron.add_command(certidude_cron_daily)
|
||||
certidude_housekeeping.add_command(certidude_housekeeping_kinit)
|
||||
certidude_housekeeping.add_command(certidude_housekeeping_expiration)
|
||||
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_enroll)
|
||||
entry_point.add_command(certidude_sign)
|
||||
entry_point.add_command(certidude_revoke)
|
||||
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_test)
|
||||
|
||||
|
@ -546,7 +546,15 @@ function loadAuthority(query) {
|
||||
**/
|
||||
$("#view-dashboard").html(env.render('views/authority.html', {
|
||||
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();
|
||||
|
@ -32,7 +32,7 @@ else
|
||||
fi
|
||||
|
||||
# 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 \
|
||||
--key /etc/certidude/authority/{{ authority_name }}/host_key.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 }};
|
||||
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,
|
||||
# backend must still check if certificate was used for TLS handshake
|
||||
ssl_verify_client optional;
|
||||
ssl_client_certificate {{ directory }}/ca_cert.pem;
|
||||
ssl_client_certificate {{ authority_path }};
|
||||
|
||||
# Proxy pass to backend
|
||||
location /api/ {
|
||||
|
@ -218,7 +218,7 @@ user enrollment = multiple allowed
|
||||
|
||||
# Certificate authority keypair
|
||||
private key path = {{ ca_key }}
|
||||
certificate path = {{ ca_cert }}
|
||||
certificate path = {{ authority_path }}
|
||||
|
||||
# Private key used by nginx frontend
|
||||
self key path = {{ self_key }}
|
||||
|
@ -2,7 +2,7 @@
|
||||
cat <<\EOF > /etc/certidude/authority/{{ session.authority.hostname }}/updown
|
||||
#!/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
|
||||
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 {
|
||||
listen 80;
|
||||
server_name {{common_name}};
|
||||
rewrite ^ https://{{common_name}}$request_uri?;
|
||||
server_name {{ common_name }};
|
||||
rewrite ^ https://{{ common_name }}\$request_uri?;
|
||||
}
|
||||
|
||||
server {
|
||||
@ -10,19 +10,21 @@ server {
|
||||
add_header X-Frame-Options "DENY";
|
||||
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
|
||||
listen 443 ssl;
|
||||
server_name {{common_name}};
|
||||
server_name $NAME;
|
||||
client_max_body_size 10G;
|
||||
ssl_certificate {{certificate_path}};
|
||||
ssl_certificate_key {{key_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_pass unix:/run/php5-fpm.sock;
|
||||
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;
|
||||
}
|
||||
}
|
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_cache shared:SSL:10m;
|
||||
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-Content-Type-Options nosniff;
|
||||
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
|
||||
map $ssl_client_s_dn $ssl_client_s_dn_cn {
|
||||
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
|
||||
curl --cert-status -f -L -H "Content-type: application/pkcs10" \
|
||||
--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
|
||||
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
|
||||
|
||||
# Patch Firefox trust store on Ubuntu
|
||||
if [ ! -h /usr/lib/firefox/libnssckbi.so ]; then
|
||||
apt install p11-kit p11-kit-modules
|
||||
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
|
||||
if [ -d /usr/lib/firefox ]; then
|
||||
if [ ! -h /usr/lib/firefox/libnssckbi.so ]; then
|
||||
apt install -y p11-kit p11-kit-modules
|
||||
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
|
@ -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>
|
||||
</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 %}
|
||||
<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>
|
||||
@ -69,24 +73,48 @@
|
||||
|
||||
<!-- UNIX-like -->
|
||||
<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>
|
||||
<div class="highlight">
|
||||
|
||||
<pre class="code"><code>{% include "snippets/request-client.sh" %}</code></pre>
|
||||
</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>
|
||||
<div class="highlight">
|
||||
<pre class="code"><code>{% include "snippets/renew.sh" %}</code></pre>
|
||||
</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 -->
|
||||
<div class="tab-pane fade" id="snippet-openvpn" role="tabpanel" aria-labelledby="openvpn">
|
||||
<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 %}
|
||||
from
|
||||
<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">
|
||||
<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>
|
||||
</div>
|
||||
|
@ -273,15 +273,16 @@ def test_cli_setup_authority():
|
||||
# - SCEP disabled
|
||||
# - CRL enabled
|
||||
|
||||
assert os.system("certidude setup authority --elliptic-curve") == 0
|
||||
assert os.system("certidude provision authority --elliptic-curve") == 0
|
||||
|
||||
assert_cleanliness()
|
||||
|
||||
assert os.path.exists("/var/lib/certidude/signed/ca.example.lan.pem"), "provisioning failed"
|
||||
|
||||
# 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"
|
||||
os.system("systemctl restart certidude")
|
||||
os.system("systemctl restart nginx")
|
||||
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
|
||||
r = client().simulate_get("/api/signed/test/script/")
|
||||
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
|
||||
|
||||
r = client().simulate_post("/api/signed/test/tag/",
|
||||
@ -751,13 +752,13 @@ def test_cli_setup_authority():
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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"):
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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/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
|
||||
|
||||
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
|
||||
|
||||
result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"])
|
||||
@ -866,7 +867,7 @@ def test_cli_setup_authority():
|
||||
|
||||
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
|
||||
|
||||
result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"])
|
||||
@ -1116,16 +1117,16 @@ def test_cli_setup_authority():
|
||||
clean_client()
|
||||
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 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 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")
|
||||
|
||||
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 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/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
|
||||
|
||||
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
|
||||
|
||||
result = runner.invoke(cli, ["enroll", "--skip-self", "--no-wait"])
|
||||
@ -1178,7 +1179,7 @@ def test_cli_setup_authority():
|
||||
|
||||
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
|
||||
|
||||
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")
|
||||
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")
|
||||
|
||||
# Install packages
|
||||
@ -1321,16 +1322,13 @@ def test_cli_setup_authority():
|
||||
# Bootstrap authority again with:
|
||||
# - RSA certificates
|
||||
# - Kerberos auth
|
||||
# - OCSP disabled
|
||||
# - SCEP enabled
|
||||
# - CRL disabled
|
||||
|
||||
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("/etc/cron.daily/certidude")
|
||||
assert os.path.exists("/etc/cron.hourly/certidude")
|
||||
|
||||
|
||||
# Make modifications to /etc/certidude/server.conf so
|
||||
# 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/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/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/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
|
||||
|
||||
# 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.stat("/run/certidude/krb5cc").st_uid != 0, "Incorrect persmissions for /run/certidude/krb5cc"
|
||||
|
||||
# Start certidude backend
|
||||
assert os.system("systemctl restart certidude") == 0
|
||||
assert os.system("systemctl restart certidude-backend") == 0
|
||||
|
||||
cov_finished = False
|
||||
for path in os.listdir("/tmp/"):
|
||||
@ -1393,14 +1390,6 @@ def test_cli_setup_authority():
|
||||
r = requests.post("http://ca.example.lan/api/scep/")
|
||||
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 ###
|
||||
@ -1460,7 +1449,7 @@ def test_cli_setup_authority():
|
||||
clean_client()
|
||||
|
||||
# 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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
for path in os.listdir("/tmp/"):
|
||||
|
Loading…
Reference in New Issue
Block a user