Compare commits
No commits in common. "5825aa52e88f0ab9a721d3b7b5cfc89cff686c5d" and "95b24cbadcd8a90a5d82d5c09512a5b02cdfbe22" have entirely different histories.
5825aa52e8
...
95b24cbadc
|
@ -1 +0,0 @@
|
|||
11
|
|
@ -1,102 +0,0 @@
|
|||
Source: lemur
|
||||
Section: admin
|
||||
Priority: extra
|
||||
Maintainer: Cadoles <contact@cadoles.com>
|
||||
Build-depends: debhelper (>=11),
|
||||
python3-all,
|
||||
python3-setuptools,
|
||||
dh-python,
|
||||
git,
|
||||
npm
|
||||
Standards-Version: 3.9.4
|
||||
Homepage: https://forge.cadoles.com/Infra/lemur
|
||||
|
||||
Package: lemur
|
||||
Architecture: any
|
||||
Pre-Depends: dpkg, python3, ${misc:Pre-Depends}
|
||||
Depends: ${python:Depends}, ${misc:Depends},
|
||||
python3-lemur
|
||||
Description: Lemur
|
||||
|
||||
Package: python3-lemur
|
||||
Architecture: any
|
||||
Pre-Depends: dpkg, python3, ${misc:Pre-Depends}
|
||||
Depends: python3-acme,
|
||||
python3-alembic,
|
||||
python3-amqp,
|
||||
python3-aniso8601,
|
||||
python3-arrow,
|
||||
python3-bcrypt,
|
||||
python3-bs4,
|
||||
python3-billiard,
|
||||
python3-blinker,
|
||||
python3-boto3,
|
||||
python3-botocore,
|
||||
python3-celery,
|
||||
python3-certifi,
|
||||
python3-cffi,
|
||||
python3-chardet,
|
||||
python3-click,
|
||||
python3-cloudflare,
|
||||
python3-dnspython,
|
||||
python3-flask-bcrypt,
|
||||
python3-flask-cors,
|
||||
python3-flask-mail,
|
||||
python3-flask-migrate,
|
||||
python3-flask-principal,
|
||||
python3-flask-restful,
|
||||
python3-flask-script,
|
||||
python3-flask-sqlalchemy,
|
||||
python3-flask,
|
||||
python3-future,
|
||||
python3-gunicorn,
|
||||
python3-hvac,
|
||||
python3-idna,
|
||||
python3-inflection,
|
||||
python3-itsdangerous,
|
||||
python3-jinja2,
|
||||
python3-jmespath,
|
||||
python3-josepy,
|
||||
python3-kombu,
|
||||
python3-lockfile,
|
||||
python3-mako,
|
||||
python3-markupsafe,
|
||||
python3-marshmallow-sqlalchemy,
|
||||
python3-ndg-httpsclient,
|
||||
python3-paramiko,
|
||||
python3-pem,
|
||||
python3-psycopg2,
|
||||
python3-pyasn1-modules,
|
||||
python3-pyasn1,
|
||||
python3-pycparser,
|
||||
python3-jwt,
|
||||
python3-nacl,
|
||||
python3-openssl,
|
||||
python3-rfc3339,
|
||||
python3-dateutil,
|
||||
python3-editor,
|
||||
python3-pythonjsonlogger,
|
||||
python3-ldap,
|
||||
python3-tz,
|
||||
python3-yaml,
|
||||
python3-redis,
|
||||
python3-requests-toolbelt,
|
||||
python3-requests,
|
||||
python3-retrying,
|
||||
python3-s3transfer,
|
||||
python3-six,
|
||||
python3-soupsieve,
|
||||
python3-sqlalchemy-utils,
|
||||
python3-sqlalchemy,
|
||||
python3-tabulate,
|
||||
python3-urllib3,
|
||||
python3-vine,
|
||||
python3-werkzeug,
|
||||
python3-xmltodict
|
||||
Description: Lemur - library part
|
||||
|
||||
Package: lemur-static
|
||||
Architecture: any
|
||||
Pre-Depends: ${misc:Pre-Depends}
|
||||
Depends: ${misc:Depends}
|
||||
Description: static HTML/JS/CSS file
|
|
@ -1,10 +0,0 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: lemur
|
||||
Upstream-Contact: Cadoles <contact@cadoles.com>
|
||||
Source: https://forge.cadoles.com/Infra/lemur
|
||||
|
||||
Files: *
|
||||
Copyright: Lemur
|
||||
License: Apache-2.0 License
|
||||
|
||||
License: Apache-2.0 License
|
|
@ -1,2 +0,0 @@
|
|||
lemur/static/dist/* usr/share/lemur/static/
|
||||
lemur/migrations usr/share/lemur
|
|
@ -1,28 +0,0 @@
|
|||
#!/usr/bin/make -f
|
||||
# See debhelper(7) (uncomment to enable)
|
||||
# output every command that modifies files on the build system.
|
||||
#DH_VERBOSE = 1
|
||||
|
||||
export PYBUILD_NAME = lemur
|
||||
export PYBUILD_DISABLE_python3 = test
|
||||
|
||||
%:
|
||||
# suppression requirements version of package
|
||||
# only last version are supported by lemur
|
||||
# but Ubuntu has not last version
|
||||
sed -i "s/==\(\([[:digit:]]\)*\(\.\)*\)*//g" requirements.txt
|
||||
dh $@ --with python3 --buildsystem=pybuild
|
||||
|
||||
override_dh_install:
|
||||
rm -rf debian/python3-lemur/usr/lib/python*/dist-packages/lemur/static/
|
||||
rm -rf debian/python3-lemur/usr/lib/python*/dist-packages/lemur/tests/
|
||||
rm -rf debian/python3-lemur/usr/lib/python*/dist-packages/trustores
|
||||
mkdir -p debian/lemur/usr
|
||||
mv debian/python3-lemur/usr/bin debian/lemur/usr
|
||||
dh_install
|
||||
|
||||
override_dh_auto_build:
|
||||
npm install --unsafe-perm
|
||||
node_modules/.bin/gulp build
|
||||
node_modules/.bin/gulp package --urlContextPath=lemur
|
||||
dh_auto_build
|
|
@ -1 +0,0 @@
|
|||
3.0 (quilt)
|
|
@ -555,122 +555,3 @@ Using `python-jwt` converting an existing private key in PEM format is quite eas
|
|||
{"body": {}, "uri": "https://acme-staging-v02.api.letsencrypt.org/acme/acct/<ACCOUNT_NUMBER>"}
|
||||
|
||||
The URI can be retrieved from the ACME create account endpoint when creating a new account, using the existing key.
|
||||
|
||||
OpenSSH
|
||||
=======
|
||||
|
||||
OpenSSH (also known as OpenBSD Secure Shell) is a suite of secure networking utilities based on the Secure Shell (SSH) protocol, which provides a secure channel over an unsecured network in a client–server architecture.
|
||||
|
||||
Using a PKI with OpenSSH means you can sign a key for a user and it can log into any server that trust the CA.
|
||||
|
||||
Using a CA avoids TOFU or synchronize a list of server public keys to `known_hosts` files.
|
||||
|
||||
This is useful when you're managing large number of machines or for an immutable infrastructure.
|
||||
|
||||
Add first OpenSSH authority
|
||||
---------------------------
|
||||
|
||||
To start issuing OpenSSH, you need to create an OpenSSH authority. To do this, visit
|
||||
Authorities -> Create. Set the applicable attributes:
|
||||
|
||||
- Name : OpenSSH
|
||||
- Common Name: example.net
|
||||
|
||||
Then click "More Options" and change the plugin value to "OpenSSH".
|
||||
|
||||
Just click to "Create" button to add this authority.
|
||||
|
||||
.. note:: OpenSSH do not support sub CA feature.
|
||||
|
||||
Add a server certificate
|
||||
-------------------------
|
||||
|
||||
Now visit Certificates -> Create to add a server certificate. Set the applicable attributes:
|
||||
|
||||
- Common Name: server.example.net
|
||||
|
||||
Then click "More Options" and set the Certificate Template to "Server Certificate".
|
||||
|
||||
This step is important, a certificat for a server and for a client is not exactly the same thing.
|
||||
In this case "Common Name" and all Subject Alternate Names with type DNSName will be added in the certificate.
|
||||
|
||||
Finally click on "Create" button.
|
||||
|
||||
Add a client certificate
|
||||
------------------------
|
||||
|
||||
Now visit Certificates -> Create to add a client certificate. Set the applicable attributes:
|
||||
|
||||
- Common Name: example.net
|
||||
|
||||
Then click "More Options" and set the Certificate Template to "Client Certificate".
|
||||
|
||||
In this case the name of the creator is used as principal (in this documentation we assume that this certificate is created by the user "lemur").
|
||||
|
||||
Finally click on "Create" button.
|
||||
|
||||
Configure OpenSSH server
|
||||
------------------------
|
||||
|
||||
Connect to the server.example.net server to correctly configure the OpenSSH server with the CA created previously.
|
||||
|
||||
First of all add the CA chain, private and public certificates:
|
||||
|
||||
- Create file `/etc/ssh/ca.pub` and copy the "CHAIN" content of the *server certificate* (everything in one line).
|
||||
- Create file `/etc/ssh/ssh_host_key` and copy "PRIVATE KEY" content.
|
||||
- Create file `/etc/ssh/ssh_host_key.pub` and copy "PUBLIC CERTIFICATE" content (everything in one line).
|
||||
|
||||
Set the appropriate right:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
chmod 600 /etc/ssh/ca.pub /etc/ssh/ssh_host_key
|
||||
chmod 644 /etc/ssh/ssh_host_key.pub
|
||||
chown root: /etc/ssh/ca.pub /etc/ssh/ssh_host_key /etc/ssh/ssh_host_key.pub
|
||||
|
||||
Then change OpenSSH server configuration to use these files. Edit `/etc/ssh/sshd_config` and add::
|
||||
|
||||
TrustedUserCAKeys /etc/ssh/ca.pub
|
||||
HostKey /etc/ssh/ssh_host_key
|
||||
HostCertificate /etc/ssh/ssh_host_key.pub
|
||||
|
||||
You can remove all other `HostKey` lines.
|
||||
|
||||
Finally restart OpenSSH.
|
||||
|
||||
.. note:: By default the server public certificate is sign for 2 weeks. You must update the `/etc/ssh/ssh_host_key.pub` file before this delay. You can use the config's parameter OPENSSH_VALID_INTERVAL_SERVER to change this behavor (unit is number of day).
|
||||
|
||||
Configure the OpenSSH client
|
||||
----------------------------
|
||||
|
||||
Now you can configure the user's computer.
|
||||
|
||||
First of all add private and public certificates:
|
||||
|
||||
- Create file `~/.ssh/key` and copy "PRIVATE KEY" content.
|
||||
- Create file `~/.ssh/key.pub` and copy "PUBLIC CERTIFICATE" content of the *client certicate* (everything in one line).
|
||||
|
||||
Set the appropriate right:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
chmod 600 ~/.ssh/key.pub ~/.ssh/key
|
||||
|
||||
To avoid TOFU, edite the `~/.ssh/known_hosts` file and add a new line (all in one line):
|
||||
|
||||
- @cert-authority \*example.net
|
||||
- the "CHAIN" content
|
||||
|
||||
Now you can connect to server with (here 'lemur' is the principal name and must exists on the server):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ssh lemur@server.example.net -i ~/.ssh/key
|
||||
|
||||
With this configuration you don't have any line like::
|
||||
|
||||
Warning: Permanently added 'server.example.net,192.168.0.1' (RSA) to the list of known hosts.
|
||||
|
||||
And you don't have to enter any password.
|
||||
|
||||
.. note:: By default the client public certificate is sign for 1 day. You must update the `.ssh/key.pub` everyday. You can use the config's parameter OPENSSH_VALID_INTERVAL_CLIENT to change this behavor (unit is number of day).
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"""
|
||||
from flask import current_app
|
||||
|
||||
from marshmallow import fields, validates_schema, pre_load, post_dump
|
||||
from marshmallow import fields, validates_schema, pre_load
|
||||
from marshmallow import validate
|
||||
from marshmallow.exceptions import ValidationError
|
||||
|
||||
|
@ -24,7 +24,6 @@ from lemur.common import validators, missing
|
|||
|
||||
from lemur.common.fields import ArrowDateTime
|
||||
from lemur.constants import CERTIFICATE_KEY_TYPES
|
||||
from lemur.plugins.base import plugins
|
||||
|
||||
|
||||
class AuthorityInputSchema(LemurInputSchema):
|
||||
|
@ -130,12 +129,6 @@ class AuthorityOutputSchema(LemurOutputSchema):
|
|||
default_validity_days = fields.Integer()
|
||||
authority_certificate = fields.Nested(RootAuthorityCertificateOutputSchema)
|
||||
|
||||
@post_dump
|
||||
def handle_auth_certificate(self, cert):
|
||||
# Plugins may need to modify the cert object before returning it to the user
|
||||
plugin = plugins.get(cert['plugin']['slug'])
|
||||
plugin.wrap_auth_certificate(cert['authority_certificate'])
|
||||
|
||||
|
||||
class AuthorityNestedOutputSchema(LemurOutputSchema):
|
||||
__envelope__ = False
|
||||
|
|
|
@ -38,7 +38,6 @@ from lemur.schemas import (
|
|||
AssociatedRotationPolicySchema,
|
||||
)
|
||||
from lemur.users.schemas import UserNestedOutputSchema
|
||||
from lemur.plugins.base import plugins
|
||||
|
||||
|
||||
class CertificateSchema(LemurInputSchema):
|
||||
|
@ -325,8 +324,6 @@ class CertificateOutputSchema(LemurOutputSchema):
|
|||
notifications = fields.Nested(NotificationNestedOutputSchema, many=True)
|
||||
replaces = fields.Nested(CertificateNestedOutputSchema, many=True)
|
||||
authority = fields.Nested(AuthorityNestedOutputSchema)
|
||||
# if this certificate is an authority, the authority informations are in root_authority
|
||||
root_authority = fields.Nested(AuthorityNestedOutputSchema)
|
||||
dns_provider = fields.Nested(DnsProvidersNestedOutputSchema)
|
||||
roles = fields.Nested(RoleNestedOutputSchema, many=True)
|
||||
endpoints = fields.Nested(EndpointNestedOutputSchema, many=True, missing=[])
|
||||
|
@ -360,16 +357,6 @@ class CertificateOutputSchema(LemurOutputSchema):
|
|||
if field in data and data[field] is None:
|
||||
data.pop(field)
|
||||
|
||||
@post_dump
|
||||
def handle_certificate(self, cert):
|
||||
# Plugins may need to modify the cert object before returning it to the user
|
||||
if cert['root_authority'] and cert['authority'] is None:
|
||||
# this certificate is an authority
|
||||
cert['authority'] = cert['root_authority']
|
||||
del cert['root_authority']
|
||||
plugin = plugins.get(cert['authority']['plugin']['slug'])
|
||||
plugin.wrap_certificate(cert)
|
||||
|
||||
|
||||
class CertificateShortOutputSchema(LemurOutputSchema):
|
||||
id = fields.Integer()
|
||||
|
|
|
@ -87,16 +87,6 @@ def get_by_attributes(conditions):
|
|||
return database.find_all(query, Certificate, conditions).all()
|
||||
|
||||
|
||||
def get_by_root_authority(id):
|
||||
"""
|
||||
Retrieves certificate by its root_authority's id.
|
||||
|
||||
:param id:
|
||||
:return:
|
||||
"""
|
||||
return database.get(Certificate, id, field="root_authority_id")
|
||||
|
||||
|
||||
def delete(cert_id):
|
||||
"""
|
||||
Delete's a certificate.
|
||||
|
|
|
@ -675,16 +675,6 @@ class CertificatePrivateKey(AuthenticatedResource):
|
|||
return dict(message="You are not authorized to view this key"), 403
|
||||
|
||||
log_service.create(g.current_user, "key_view", certificate=cert)
|
||||
|
||||
# Plugins may need to modify the cert object before returning it to the user
|
||||
if cert.root_authority:
|
||||
# this certificate is an authority
|
||||
plugin_name = cert.root_authority.plugin_name
|
||||
else:
|
||||
plugin_name = cert.authority.plugin_name
|
||||
plugin = plugins.get(plugin_name)
|
||||
plugin.wrap_private_key(cert)
|
||||
|
||||
response = make_response(jsonify(key=cert.private_key), 200)
|
||||
response.headers["cache-control"] = "private, max-age=0, no-cache, no-store"
|
||||
response.headers["pragma"] = "no-cache"
|
||||
|
|
|
@ -31,12 +31,3 @@ class IssuerPlugin(Plugin):
|
|||
|
||||
def cancel_ordered_certificate(self, pending_cert, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
def wrap_certificate(self, cert):
|
||||
pass
|
||||
|
||||
def wrap_auth_certificate(self, cert):
|
||||
pass
|
||||
|
||||
def wrap_private_key(self, cert):
|
||||
pass
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
try:
|
||||
VERSION = __import__("pkg_resources").get_distribution(__name__).version
|
||||
except Exception as e:
|
||||
VERSION = "unknown"
|
|
@ -1,152 +0,0 @@
|
|||
"""
|
||||
.. module: lemur.plugins.lemur_openssh.plugin
|
||||
:platform: Unix
|
||||
:copyright: (c) 2020 by Emmanuel Garette, see AUTHORS for more
|
||||
:license: Apache, see LICENSE for more details.
|
||||
|
||||
.. moduleauthor:: Emmanuel Garette <gnunux@gnunux.info>
|
||||
"""
|
||||
import subprocess
|
||||
from os import unlink
|
||||
|
||||
from flask import current_app
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from lemur.utils import mktempfile
|
||||
from lemur.plugins import lemur_openssh as openssh
|
||||
from lemur.common.utils import parse_private_key, parse_certificate
|
||||
from lemur.plugins.lemur_cryptography.plugin import CryptographyIssuerPlugin
|
||||
from lemur.certificates.service import get_by_root_authority
|
||||
|
||||
|
||||
def run_process(command):
|
||||
"""
|
||||
Runs a given command with pOpen and wraps some
|
||||
error handling around it.
|
||||
:param command:
|
||||
:return:
|
||||
"""
|
||||
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
current_app.logger.debug(" ".join(command))
|
||||
stdout, stderr = p.communicate()
|
||||
|
||||
if p.returncode != 0:
|
||||
current_app.logger.error(stderr.decode())
|
||||
raise Exception(stderr.decode())
|
||||
|
||||
|
||||
def split_cert(body):
|
||||
"""
|
||||
To display certificate in Lemur website, we have to split
|
||||
certificate in several line
|
||||
:param body: certificate
|
||||
:retur: splitted certificate
|
||||
"""
|
||||
length = 65
|
||||
return '\n'.join([body[i:i + length] for i in range(0, len(body), length)])
|
||||
|
||||
|
||||
def sign_certificate(common_name, public_key, authority_private_key, user, extensions, not_before, not_after):
|
||||
with mktempfile() as issuer_tmp:
|
||||
cmd = ['ssh-keygen', '-s', issuer_tmp]
|
||||
with open(issuer_tmp, 'w') as i:
|
||||
i.writelines(authority_private_key)
|
||||
if 'extendedKeyUsage' in extensions and extensions['extendedKeyUsage'].get('useClientAuthentication'):
|
||||
valid_interval = current_app.config.get("OPENSSH_VALID_INTERVAL_CLIENT", 1) # 1 day by default
|
||||
cmd.extend(['-I', user['username'] + ' user key',
|
||||
'-n', user['username']])
|
||||
else:
|
||||
valid_interval = current_app.config.get("OPENSSH_VALID_INTERVAL_SERVER", 14) # 2 weeks by default
|
||||
domains = {common_name}
|
||||
for name in extensions['subAltNames']['names']:
|
||||
if name['nameType'] == 'DNSName':
|
||||
domains.add(name['value'])
|
||||
cmd.extend(['-I', common_name + ' host key',
|
||||
'-n', ','.join(domains),
|
||||
'-h'])
|
||||
# something like 20201024
|
||||
ssh_not_before = datetime.fromisoformat(not_before).strftime("%Y%m%d")
|
||||
cert_not_after = datetime.fromisoformat(not_after).strftime("%Y%m%d")
|
||||
ssh_not_after = (datetime.now() + timedelta(days=valid_interval)).strftime("%Y%m%d")
|
||||
ssh_not_after = min(ssh_not_after, cert_not_after)
|
||||
cmd.extend(['-V', ssh_not_before + ':' + ssh_not_after])
|
||||
with mktempfile() as cert_tmp:
|
||||
with open(cert_tmp, 'w') as f:
|
||||
f.write(public_key)
|
||||
|
||||
cmd.append(cert_tmp)
|
||||
run_process(cmd)
|
||||
pub = cert_tmp + '-cert.pub'
|
||||
with open(pub, 'r') as p:
|
||||
body = split_cert(p.read())
|
||||
unlink(pub)
|
||||
return body
|
||||
|
||||
|
||||
class OpenSSHIssuerPlugin(CryptographyIssuerPlugin):
|
||||
"""This issuer plugins is base in Cryptography plugin
|
||||
Certificates and authorities are x509 certificates created by Cryptography plugin.
|
||||
Those certificates are converted to OpenSSH format when people get them.
|
||||
"""
|
||||
title = "OpenSSH"
|
||||
slug = "openssh-issuer"
|
||||
description = "Enables the creation and signing OpenSSH keys"
|
||||
version = openssh.VERSION
|
||||
|
||||
author = "Emmanuel Garette"
|
||||
author_url = "http://gnunux.info"
|
||||
|
||||
def create_authority(self, options):
|
||||
# OpenSSH do not support parent's authoriy
|
||||
if options.get("parent"):
|
||||
raise Exception('cannot create authority with a parent for OpenSSH plugin')
|
||||
# create a x509 certificat
|
||||
cert_pem, private_key, chain_cert_pem, roles = super().create_authority(options)
|
||||
return cert_pem, private_key, chain_cert_pem, roles
|
||||
|
||||
def wrap_certificate(self, cert):
|
||||
# get public_key in OpenSSH format
|
||||
public_key = parse_certificate(cert['body']).public_key().public_bytes(
|
||||
encoding=serialization.Encoding.OpenSSH,
|
||||
format=serialization.PublicFormat.OpenSSH,
|
||||
).decode()
|
||||
public_key += ' ' + cert['user']['email']
|
||||
# sign it with authority private key
|
||||
authority = get_by_root_authority(cert['authority']['id'])
|
||||
authority_private_key = authority.private_key
|
||||
cert['body'] = sign_certificate(
|
||||
cert['common_name'],
|
||||
public_key,
|
||||
authority_private_key,
|
||||
cert['user'],
|
||||
cert['extensions'],
|
||||
cert['not_before'],
|
||||
cert['not_after']
|
||||
)
|
||||
# convert chain in OpenSSH format
|
||||
if cert['chain']:
|
||||
chain_cert = {'body': cert['chain'], 'cn': authority.cn}
|
||||
self.wrap_auth_certificate(chain_cert)
|
||||
cert['chain'] = chain_cert['body']
|
||||
# OpenSSH do not support csr
|
||||
cert['csr'] = None
|
||||
|
||||
@staticmethod
|
||||
def wrap_auth_certificate(auth_cert):
|
||||
# convert chain in OpenSSH format
|
||||
chain_key = parse_certificate(auth_cert['body']).public_key().public_bytes(
|
||||
encoding=serialization.Encoding.OpenSSH,
|
||||
format=serialization.PublicFormat.OpenSSH,
|
||||
).decode()
|
||||
chain_key += ' root@' + auth_cert['cn']
|
||||
auth_cert['body'] = split_cert(chain_key)
|
||||
|
||||
@staticmethod
|
||||
def wrap_private_key(cert):
|
||||
# convert private_key in OpenSSH format
|
||||
cert.private_key = parse_private_key(cert.private_key).private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.OpenSSH,
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
)
|
3
setup.py
3
setup.py
|
@ -157,8 +157,7 @@ setup(
|
|||
'adcs_issuer = lemur.plugins.lemur_adcs.plugin:ADCSIssuerPlugin',
|
||||
'adcs_source = lemur.plugins.lemur_adcs.plugin:ADCSSourcePlugin',
|
||||
'entrust_issuer = lemur.plugins.lemur_entrust.plugin:EntrustIssuerPlugin',
|
||||
'entrust_source = lemur.plugins.lemur_entrust.plugin:EntrustSourcePlugin',
|
||||
'openssh_issuer = lemur.plugins.lemur_openssh.plugin:OpenSSHIssuerPlugin',
|
||||
'entrust_source = lemur.plugins.lemur_entrust.plugin:EntrustSourcePlugin'
|
||||
],
|
||||
},
|
||||
classifiers=[
|
||||
|
|
Loading…
Reference in New Issue