mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
monkeysphere: Reorganize around keys instead
- Read Apache configuration to find the list of all available certificates and their associated domains. Use this for setting UIDs properly. - Solve the issue of re-importing renewed certficiate. Use the SSH fingerprints as unique keys instead of domain names. Compute SSH fingerprints for SSH keys and HTTPS certficates inorder accurately identify if they are currently imported into monkeysphere. - Allow having more than one domains for a certficiate. Add action to import new domains to an existing monkeysphere OpenPGP key. - Import only once for a given certficiate and keep adding UIDs when domains get added. - Merge services SSH and HTTPS giving us the ability to deals with many more services. Remove special handling for different kinds of certificate sources. - Supress monkeysphere prompts in case of reusing UIDs.
This commit is contained in:
parent
28856d96a3
commit
f4601e7b05
@ -21,8 +21,10 @@ Configuration helper for monkeysphere.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import augeas
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
|
||||
@ -32,24 +34,16 @@ def parse_arguments():
|
||||
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
|
||||
|
||||
host_show_keys = subparsers.add_parser(
|
||||
'host-show-keys', help='Show host key fingerprints')
|
||||
'host-show-keys', help='Show imported/importable keys')
|
||||
host_show_keys.add_argument(
|
||||
'key_ids', nargs='*', help='Optional list of KEYIDs')
|
||||
'key_id', nargs='?', help='Optional KEYID to retrieve details for')
|
||||
|
||||
host_import_ssh_key = subparsers.add_parser(
|
||||
'host-import-ssh-key', help='Import host SSH key')
|
||||
host_import_ssh_key.add_argument(
|
||||
'domain', help='Fully-qualified domain name')
|
||||
|
||||
host_import_snakeoil_key = subparsers.add_parser(
|
||||
'host-import-snakeoil-key', help='Import host snakeoil key')
|
||||
host_import_snakeoil_key.add_argument(
|
||||
'domain', help='Fully-qualified domain name')
|
||||
|
||||
host_import_letsencrypt_key = subparsers.add_parser(
|
||||
'host-import-letsencrypt-key', help="Import Let's Encrypt key")
|
||||
host_import_letsencrypt_key.add_argument(
|
||||
'domain', help='Fully-qualified domain name')
|
||||
host_import_key = subparsers.add_parser(
|
||||
'host-import-key', help='Import a key into monkeysphere')
|
||||
host_import_key.add_argument(
|
||||
'ssh_fingerprint', help='SSH fingerprint of the key to import')
|
||||
host_import_key.add_argument(
|
||||
'domains', nargs='*', help='List of available domains')
|
||||
|
||||
host_publish_key = subparsers.add_parser(
|
||||
'host-publish-key', help='Push host key to keyserver')
|
||||
@ -59,16 +53,75 @@ def parse_arguments():
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def subcommand_host_show_keys(arguments):
|
||||
"""Show host key fingerprints."""
|
||||
try:
|
||||
def get_ssh_keys():
|
||||
"""Return all SSH keys."""
|
||||
keys = {}
|
||||
|
||||
key_files = ['/etc/ssh/ssh_host_rsa_key']
|
||||
for key_file in key_files:
|
||||
output = subprocess.check_output(
|
||||
['monkeysphere-host', 'show-keys'] + arguments.key_ids,
|
||||
['ssh-keygen', '-l', '-E', 'MD5', '-f', key_file])
|
||||
fingerprint = output.decode().split()[1].lstrip('MD5:')
|
||||
keys[fingerprint] = {'ssh_fingerprint': fingerprint,
|
||||
'service': 'ssh',
|
||||
'key_file': key_file,
|
||||
'available_domains': ['*']}
|
||||
|
||||
return keys
|
||||
|
||||
|
||||
def get_pem_ssh_fingerprint(pem_file):
|
||||
"""Return the SSH fingerprint of a PEM file."""
|
||||
public_key = subprocess.check_output(
|
||||
['openssl', 'rsa', '-in', pem_file, '-pubout'],
|
||||
stderr=subprocess.DEVNULL)
|
||||
ssh_public_key = subprocess.check_output(
|
||||
['ssh-keygen', '-i', '-m', 'PKCS8', '-f', '/dev/stdin'],
|
||||
input=public_key)
|
||||
fingerprint = subprocess.check_output(
|
||||
['ssh-keygen', '-l', '-E', 'md5', '-f', '/dev/stdin'],
|
||||
input=ssh_public_key)
|
||||
|
||||
return fingerprint.decode().split()[1].lstrip('MD5:')
|
||||
|
||||
|
||||
def get_https_keys():
|
||||
"""Return all HTTPS keys."""
|
||||
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
|
||||
augeas.Augeas.NO_MODL_AUTOLOAD)
|
||||
aug.set('/augeas/load/Httpd/lens', 'Httpd.lns')
|
||||
aug.set('/augeas/load/Httpd/incl[last() + 1]',
|
||||
'/etc/apache2/sites-available/*')
|
||||
aug.load()
|
||||
|
||||
keys = {}
|
||||
path = '/files/etc/apache2/sites-available//VirtualHost'
|
||||
for match in aug.match(path):
|
||||
host = {'available_domains': ['*'], 'service': 'https'}
|
||||
for directive in aug.match(match + '/directive'):
|
||||
name = aug.get(directive)
|
||||
if name == 'ServerName':
|
||||
host['available_domains'] = [aug.get(directive + '/arg')]
|
||||
elif name in ('GnuTLSKeyFile', 'SSLCertificateKeyFile'):
|
||||
host['key_file'] = aug.get(directive + '/arg')
|
||||
|
||||
if 'key_file' in host:
|
||||
host['ssh_fingerprint'] = get_pem_ssh_fingerprint(host['key_file'])
|
||||
keys[host['ssh_fingerprint']] = host
|
||||
|
||||
return keys
|
||||
|
||||
|
||||
def get_monkeysphere_keys(key_id=None):
|
||||
"""Return the list of keys imported into monkeysphere."""
|
||||
try:
|
||||
key_ids = [] if not key_id else [key_id]
|
||||
output = subprocess.check_output(
|
||||
['monkeysphere-host', 'show-keys'] + key_ids,
|
||||
stderr=subprocess.DEVNULL)
|
||||
except subprocess.CalledProcessError:
|
||||
# no keys available
|
||||
print(json.dumps({'keys': []}))
|
||||
return
|
||||
return {}
|
||||
|
||||
# parse output
|
||||
keys = [dict()]
|
||||
@ -79,9 +132,15 @@ def subcommand_host_show_keys(arguments):
|
||||
keys[-1]['pub'] = data[0]
|
||||
keys[-1]['date'] = data[1]
|
||||
elif line.startswith('uid'):
|
||||
keys[-1]['uid'] = line.lstrip('uid').strip()
|
||||
uid = line.lstrip('uid').strip()
|
||||
keys[-1].setdefault('uids', []).append(uid)
|
||||
matches = re.match('([a-zA-Z]*)://(.*)(:\d*)?', uid)
|
||||
keys[-1]['service'] = matches.group(1)
|
||||
keys[-1].setdefault('imported_domains', []) \
|
||||
.append(matches.group(2))
|
||||
elif line.startswith('OpenPGP fingerprint:'):
|
||||
keys[-1]['pgp_fingerprint'] = line.lstrip('Open PGP fingerprint:')
|
||||
keys[-1]['openpgp_fingerprint'] = \
|
||||
line.lstrip('OpenPGP fingerprint:')
|
||||
elif line.startswith('ssh fingerprint:'):
|
||||
data = line.lstrip('ssh fingerprint:').split()
|
||||
keys[-1]['ssh_key_size'] = data[0]
|
||||
@ -90,52 +149,60 @@ def subcommand_host_show_keys(arguments):
|
||||
elif line == '':
|
||||
keys.append(dict())
|
||||
|
||||
print(json.dumps({'keys': keys}))
|
||||
return {key['ssh_fingerprint']: key for key in keys}
|
||||
|
||||
|
||||
def subcommand_host_import_ssh_key(arguments):
|
||||
def get_merged_keys(key_id=None):
|
||||
"""Return merged list of system and monkeysphere keys."""
|
||||
keys = get_monkeysphere_keys(key_id)
|
||||
|
||||
system_keys = list(get_ssh_keys().items()) + list(get_https_keys().items())
|
||||
for ssh_fingerprint, key in system_keys:
|
||||
if key_id and ssh_fingerprint not in keys:
|
||||
continue
|
||||
|
||||
if ssh_fingerprint in keys:
|
||||
keys[ssh_fingerprint].update({
|
||||
'available_domains': key['available_domains'],
|
||||
'key_file': key['key_file']})
|
||||
else:
|
||||
keys[ssh_fingerprint] = key
|
||||
|
||||
return keys
|
||||
|
||||
|
||||
def subcommand_host_show_keys(arguments):
|
||||
"""Show host key fingerprints."""
|
||||
print(json.dumps({'keys': get_merged_keys(arguments.key_id)}))
|
||||
|
||||
|
||||
def subcommand_host_import_key(arguments, second_run=False):
|
||||
"""Import host SSH key."""
|
||||
output = subprocess.check_output(
|
||||
['monkeysphere-host', 'import-key',
|
||||
'/etc/ssh/ssh_host_rsa_key', 'ssh://' + arguments.domain])
|
||||
print(output.decode())
|
||||
keys = get_merged_keys()
|
||||
if arguments.ssh_fingerprint not in keys:
|
||||
raise Exception('Unknown SSH fingerprint')
|
||||
|
||||
key = keys[arguments.ssh_fingerprint]
|
||||
if '*' in key['available_domains']:
|
||||
key['available_domains'] = arguments.domains
|
||||
|
||||
def subcommand_host_import_snakeoil_key(arguments):
|
||||
"""Import host snakeoil key."""
|
||||
proc = subprocess.Popen(
|
||||
['monkeysphere-host', 'import-key',
|
||||
'/etc/ssl/private/ssl-cert-snakeoil.key',
|
||||
'https://' + arguments.domain],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
env=dict(
|
||||
os.environ,
|
||||
MONKEYSPHERE_PROMPT='false'))
|
||||
output, error = proc.communicate()
|
||||
output, error = output.decode(), error.decode()
|
||||
if proc.returncode != 0:
|
||||
raise Exception(output, error)
|
||||
if 'openpgp_fingerprint' not in key and not second_run:
|
||||
env = dict(os.environ, MONKEYSPHERE_PROMPT='false')
|
||||
subprocess.check_call(
|
||||
['monkeysphere-host', 'import-key',
|
||||
key['key_file'], key['service'] + '://' +
|
||||
key['available_domains'][0]], env=env)
|
||||
subcommand_host_import_key(arguments, second_run=True)
|
||||
else:
|
||||
for domain in key['available_domains']:
|
||||
if domain in key['imported_domains']:
|
||||
continue
|
||||
|
||||
print(output)
|
||||
|
||||
|
||||
def subcommand_host_import_letsencrypt_key(arguments):
|
||||
"""Import Let's Encrypt key."""
|
||||
proc = subprocess.Popen(
|
||||
['monkeysphere-host', 'import-key',
|
||||
os.path.join('/etc/letsencrypt/live',
|
||||
arguments.domain, 'privkey.pem'),
|
||||
'https://' + arguments.domain],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
env=dict(
|
||||
os.environ,
|
||||
MONKEYSPHERE_PROMPT='false'))
|
||||
output, error = proc.communicate()
|
||||
output, error = output.decode(), error.decode()
|
||||
if proc.returncode != 0:
|
||||
raise Exception(output, error)
|
||||
|
||||
print(output)
|
||||
env = dict(os.environ, MONKEYSPHERE_PROMPT='false')
|
||||
subprocess.check_call(
|
||||
['monkeysphere-host', 'add-servicename',
|
||||
key['service'] + '://' + domain, key['openpgp_fingerprint']],
|
||||
env=env)
|
||||
|
||||
|
||||
def subcommand_host_publish_key(arguments):
|
||||
|
||||
@ -27,6 +27,25 @@
|
||||
<meta http-equiv="refresh" content="3"/>
|
||||
{% endif %}
|
||||
|
||||
<style type="text/css">
|
||||
td li {
|
||||
list-style: none;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
td ul {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.form.pull-right {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.form button {
|
||||
width: 9em;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@ -47,155 +66,87 @@
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<h3>{% trans "Secure Shell (SSH)" %}</h3>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<table class="table table-bordered table-condensed table-striped">
|
||||
<div class="col-sm-10">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Domain" %}</th>
|
||||
<th>{% trans "Service" %}</th>
|
||||
<th>{% trans "Domains" %}</th>
|
||||
<th>{% trans "OpenPGP Fingerprint" %}</th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for domain in status.domains %}
|
||||
{% for key in status.keys.values %}
|
||||
<tr>
|
||||
<td>{{ domain.name }}</td>
|
||||
<td>
|
||||
{% if domain.key %}
|
||||
<a href="{% url 'monkeysphere:details' domain.key.pgp_fingerprint %}"
|
||||
title="Show details for key {{ domain.key.pgp_fingerprint }}">
|
||||
{{ domain.key.pgp_fingerprint }}
|
||||
</a>
|
||||
{% if key.service == 'ssh' %}
|
||||
{% trans "Secure Shell" %}
|
||||
{% elif key.service == 'https' %}
|
||||
{% trans "Web Server" %}
|
||||
{% else %}
|
||||
{% trans "Not Available" %}
|
||||
{% trans "Other" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if not domain.key %}
|
||||
<form class="form" method="post"
|
||||
action="{% url 'monkeysphere:generate' domain.name %}">
|
||||
<ul>
|
||||
{% for domain in key.available_domains %}
|
||||
<li>
|
||||
{% if domain in key.imported_domains %}
|
||||
<span class="label label-success"
|
||||
><span class="glyphicon glyphicon-ok" aria-hidden="true"
|
||||
></span></span>
|
||||
{% else %}
|
||||
<span class="label label-default"
|
||||
><span class="glyphicon glyphicon-remove" aria-hidden="true"
|
||||
></span></span>
|
||||
{% endif %}
|
||||
{{ domain }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
{% if key.openpgp_fingerprint %}
|
||||
<a href="{% url 'monkeysphere:details' key.openpgp_fingerprint %}"
|
||||
title="{% blocktrans trimmed with fingerprint=key.openpgp_fingerprint %}
|
||||
Show details for key {{ fingerprint }}
|
||||
{% endblocktrans %}">
|
||||
{{ key.openpgp_fingerprint }}
|
||||
</a>
|
||||
{% else %}
|
||||
{% trans "-" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if not key.openpgp_fingerprint %}
|
||||
<form class="form pull-right" method="post"
|
||||
action="{% url 'monkeysphere:import' key.ssh_fingerprint %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-sm pull-right">
|
||||
{% trans "Generate OpenPGP Key" %}</button>
|
||||
{% trans "Import Key" %}</button>
|
||||
</form>
|
||||
{% elif not running %}
|
||||
<form class="form" method="post"
|
||||
action="{% url 'monkeysphere:publish' domain.key.pgp_fingerprint %}">
|
||||
{% else %}
|
||||
{% if not running %}
|
||||
<form class="form pull-right" method="post"
|
||||
action="{% url 'monkeysphere:publish' key.openpgp_fingerprint %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<button type="submit" class="btn btn-warning btn-sm pull-right">
|
||||
{% trans "Publish Key" %}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if key.imported_domains != key.available_domains %}
|
||||
<form class="form pull-right" method="post"
|
||||
action="{% url 'monkeysphere:import' key.ssh_fingerprint %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<h3>{% trans "Secure Web Server (HTTPS)" %}</h3>
|
||||
|
||||
<h4>{% trans "Self-signed Certificate" %}</h4>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<table class="table table-bordered table-condensed table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Domain" %}</th>
|
||||
<th>{% trans "OpenPGP Fingerprint" %}</th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for domain in status.snakeoil_domains %}
|
||||
<tr>
|
||||
<td>{{ domain.name }}</td>
|
||||
<td>
|
||||
{% if domain.key %}
|
||||
<a href="{% url 'monkeysphere:details' domain.key.pgp_fingerprint %}"
|
||||
title="Show details for key {{ domain.key.pgp_fingerprint }}">
|
||||
{{ domain.key.pgp_fingerprint }}
|
||||
</a>
|
||||
{% else %}
|
||||
{% trans "Not Available" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if not domain.key %}
|
||||
<form class="form" method="post"
|
||||
action="{% url 'monkeysphere:generate_snakeoil' domain.name %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-sm pull-right">
|
||||
{% trans "Generate OpenPGP Key" %}</button>
|
||||
</form>
|
||||
{% elif not running %}
|
||||
<form class="form" method="post"
|
||||
action="{% url 'monkeysphere:publish' domain.key.pgp_fingerprint %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<button type="submit" class="btn btn-warning btn-sm pull-right">
|
||||
{% trans "Publish Key" %}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4>{% trans "Let's Encrypt Certificates" %}</h4>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<table class="table table-bordered table-condensed table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Domain" %}</th>
|
||||
<th>{% trans "OpenPGP Fingerprint" %}</th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for domain in status.letsencrypt_domains %}
|
||||
<tr>
|
||||
<td>{{ domain.name }}</td>
|
||||
<td>
|
||||
{% if domain.key %}
|
||||
<a href="{% url 'monkeysphere:details' domain.key.pgp_fingerprint %}"
|
||||
title="Show details for key {{ domain.key.pgp_fingerprint }}">
|
||||
{{ domain.key.pgp_fingerprint }}
|
||||
</a>
|
||||
{% else %}
|
||||
{% trans "Not Available" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if not domain.key %}
|
||||
<form class="form" method="post"
|
||||
action="{% url 'monkeysphere:generate_letsencrypt' domain.name %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-sm pull-right">
|
||||
{% trans "Generate OpenPGP Key" %}</button>
|
||||
</form>
|
||||
{% elif not running %}
|
||||
<form class="form" method="post"
|
||||
action="{% url 'monkeysphere:publish' domain.key.pgp_fingerprint %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<button type="submit" class="btn btn-warning btn-sm pull-right">
|
||||
{% trans "Publish Key" %}</button>
|
||||
</form>
|
||||
<button type="submit" class="btn btn-primary btn-sm pull-right">
|
||||
{% trans "Add Domains" %}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -29,18 +29,18 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{% trans "OpenPGP Fingerprint" %}</td>
|
||||
<td>{{ key.pgp_fingerprint }}</td>
|
||||
<td>{{ key.openpgp_fingerprint }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans "OpenPGP Key ID" %}</td>
|
||||
<td>{{ key.pub }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans "OpenPGP User ID" %}</td>
|
||||
<td>{{ key.uid }}</td>
|
||||
<td>{% trans "OpenPGP User IDs" %}</td>
|
||||
<td>{{ key.uids|join:', ' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans "Key Generation Date" %}</td>
|
||||
<td>{% trans "Key Import Date" %}</td>
|
||||
<td>{{ key.date }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -55,6 +55,30 @@
|
||||
<td>{% trans "SSH Fingerprint" %}</td>
|
||||
<td>{{ key.ssh_fingerprint }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans "Service" %}</td>
|
||||
<td>
|
||||
{% if key.service == 'ssh' %}
|
||||
{% trans "Secure Shell" %}
|
||||
{% elif key.service == 'https' %}
|
||||
{% trans "Web Server" %}
|
||||
{% else %}
|
||||
{% trans "Other" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans "Key File" %}</td>
|
||||
<td>{{ key.key_file }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans "Available Domains" %}</td>
|
||||
<td>{{ key.available_domains|join:', ' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans "Added Domains" %}</td>
|
||||
<td>{{ key.imported_domains|join:', ' }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -66,13 +90,13 @@
|
||||
</p>
|
||||
<pre>
|
||||
# {% trans "Download the key" %}
|
||||
gpg --recv-key {{ key.pgp_fingerprint }}
|
||||
gpg --recv-key {{ key.openpgp_fingerprint }}
|
||||
|
||||
# {% trans "Sign the key" %}
|
||||
gpg --sign-key {{ key.pgp_fingerprint }}
|
||||
gpg --sign-key {{ key.openpgp_fingerprint }}
|
||||
|
||||
# {% trans "Send the key back to the keyservers" %}
|
||||
gpg --send-key {{ key.pgp_fingerprint }}
|
||||
gpg --send-key {{ key.openpgp_fingerprint }}
|
||||
</pre>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@ -26,12 +26,8 @@ from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^sys/monkeysphere/$', views.index, name='index'),
|
||||
url(r'^sys/monkeysphere/(?P<domain>[^/]+)/generate/$',
|
||||
views.generate, name='generate'),
|
||||
url(r'^sys/monkeysphere/(?P<domain>[^/]+)/generate_snakeoil/$',
|
||||
views.generate_snakeoil, name='generate_snakeoil'),
|
||||
url(r'^sys/monkeysphere/(?P<domain>[^/]+)/generate_letsencrypt/$',
|
||||
views.generate_letsencrypt, name='generate_letsencrypt'),
|
||||
url(r'^sys/monkeysphere/(?P<ssh_fingerprint>[0-9A-Fa-f:]+)/import/$',
|
||||
views.import_key, name='import'),
|
||||
url(r'^sys/monkeysphere/(?P<fingerprint>[0-9A-Fa-f]+)/details/$',
|
||||
views.details, name='details'),
|
||||
url(r'^sys/monkeysphere/(?P<fingerprint>[0-9A-Fa-f]+)/publish/$',
|
||||
|
||||
@ -47,58 +47,27 @@ def index(request):
|
||||
|
||||
|
||||
@require_POST
|
||||
def generate(request, domain):
|
||||
"""Generate OpenPGP key for SSH service."""
|
||||
valid_domain = any((domain in domains
|
||||
for domains in names.domains.values()))
|
||||
if valid_domain:
|
||||
try:
|
||||
actions.superuser_run(
|
||||
'monkeysphere', ['host-import-ssh-key', domain])
|
||||
messages.success(request, _('Generated OpenPGP key.'))
|
||||
except actions.ActionError as exception:
|
||||
messages.error(request, str(exception))
|
||||
|
||||
return redirect(reverse_lazy('monkeysphere:index'))
|
||||
|
||||
|
||||
@require_POST
|
||||
def generate_snakeoil(request, domain):
|
||||
"""Generate OpenPGP key for snakeoil certificate."""
|
||||
valid_domain = any((domain in domains
|
||||
for domains in names.domains.values()))
|
||||
if valid_domain:
|
||||
try:
|
||||
actions.superuser_run(
|
||||
'monkeysphere', ['host-import-snakeoil-key', domain])
|
||||
messages.success(request, _('Generated OpenPGP key.'))
|
||||
except actions.ActionError as exception:
|
||||
messages.error(request, str(exception))
|
||||
|
||||
return redirect(reverse_lazy('monkeysphere:index'))
|
||||
|
||||
|
||||
@require_POST
|
||||
def generate_letsencrypt(request, domain):
|
||||
"""Generate OpenPGP key for Let's Encrypt certificate."""
|
||||
valid_domain = any((domain in domains
|
||||
for domains in names.domains.values()))
|
||||
if valid_domain:
|
||||
try:
|
||||
actions.superuser_run(
|
||||
'monkeysphere', ['host-import-letsencrypt-key', domain])
|
||||
messages.success(request, _('Generated OpenPGP key.'))
|
||||
except actions.ActionError as exception:
|
||||
messages.error(request, str(exception))
|
||||
def import_key(request, ssh_fingerprint):
|
||||
"""Import a key into monkeysphere."""
|
||||
available_domains = [domain
|
||||
for domains in names.domains.values()
|
||||
for domain in domains]
|
||||
try:
|
||||
actions.superuser_run(
|
||||
'monkeysphere', ['host-import-key', ssh_fingerprint] +
|
||||
available_domains)
|
||||
messages.success(request, _('Imported key.'))
|
||||
except actions.ActionError as exception:
|
||||
messages.error(request, str(exception))
|
||||
|
||||
return redirect(reverse_lazy('monkeysphere:index'))
|
||||
|
||||
|
||||
def details(request, fingerprint):
|
||||
"""Get details for an OpenPGP key."""
|
||||
key = get_key(fingerprint)
|
||||
return TemplateResponse(request, 'monkeysphere_details.html',
|
||||
{'title': _('Monkeysphere'), 'key': key})
|
||||
{'title': monkeysphere.title,
|
||||
'key': get_key(fingerprint)})
|
||||
|
||||
|
||||
@require_POST
|
||||
@ -126,61 +95,36 @@ def cancel(request):
|
||||
|
||||
def get_status():
|
||||
"""Get the current status."""
|
||||
output = actions.superuser_run('monkeysphere', ['host-show-keys'])
|
||||
keys = {}
|
||||
https_keys = {}
|
||||
for key in json.loads(output)['keys']:
|
||||
if key['uid'].startswith('ssh'):
|
||||
key['name'] = key['uid'].replace('ssh://', '')
|
||||
keys[key['name']] = key
|
||||
elif key['uid'].startswith('https'):
|
||||
key['name'] = key['uid'].replace('https://', '')
|
||||
https_keys[key['name']] = key
|
||||
return {'keys': get_keys()}
|
||||
|
||||
domains = []
|
||||
for domains_of_a_type in names.domains.values():
|
||||
for domain in domains_of_a_type:
|
||||
domains.append({
|
||||
'name': domain,
|
||||
'key': keys.get(domain),
|
||||
})
|
||||
|
||||
# XXX: Currently, there's no way to tell if keys in monkeysphere are for
|
||||
# snakeoil or letsencrypt certs. If snakeoil cert is imported for a domain,
|
||||
# then later that domain is activated for letsencrypt, the snakeoil cert
|
||||
# will be shown in the letsencrypt table.
|
||||
output = actions.superuser_run('letsencrypt', ['get-status'])
|
||||
letsencrypt_domains_all = json.loads(output)['domains']
|
||||
letsencrypt_domains = []
|
||||
snakeoil_domains = []
|
||||
for domains_of_a_type in names.domains.values():
|
||||
for domain in domains_of_a_type:
|
||||
if domain in letsencrypt_domains_all and \
|
||||
letsencrypt_domains_all[domain]['certificate_available']:
|
||||
letsencrypt_domains.append({
|
||||
'name': domain,
|
||||
'key': https_keys.get(domain),
|
||||
})
|
||||
else:
|
||||
snakeoil_domains.append({
|
||||
'name': domain,
|
||||
'key': https_keys.get(domain),
|
||||
})
|
||||
def get_keys(fingerprint=None):
|
||||
"""Get keys."""
|
||||
fingerprint = [fingerprint] if fingerprint else []
|
||||
output = actions.superuser_run('monkeysphere',
|
||||
['host-show-keys'] + fingerprint)
|
||||
keys = json.loads(output)['keys']
|
||||
|
||||
return {'domains': domains,
|
||||
'snakeoil_domains': snakeoil_domains,
|
||||
'letsencrypt_domains': letsencrypt_domains}
|
||||
domains = [domain
|
||||
for domains_of_a_type in names.domains.values()
|
||||
for domain in domains_of_a_type]
|
||||
for key in keys.values():
|
||||
if '*' in key['available_domains']:
|
||||
key['available_domains'] = set(domains)
|
||||
else:
|
||||
key['available_domains'] = set(key['available_domains'])
|
||||
|
||||
if 'imported_domains' in key:
|
||||
key['imported_domains'] = set(key['imported_domains']) \
|
||||
.intersection(key['available_domains'])
|
||||
|
||||
return keys
|
||||
|
||||
|
||||
def get_key(fingerprint):
|
||||
"""Get key by fingerprint."""
|
||||
output = actions.superuser_run('monkeysphere',
|
||||
['host-show-keys', fingerprint])
|
||||
if output:
|
||||
keys = json.loads(output)['keys']
|
||||
return keys[0]
|
||||
|
||||
return None
|
||||
keys = get_keys(fingerprint)
|
||||
return list(keys.values())[0] if len(keys) else None
|
||||
|
||||
|
||||
def _collect_publish_result(request):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user