Ensuring that destinations require private keys by default. (#390)
* Ensuring that destinations require private keys by default.
This commit is contained in:
parent
4ee1c21144
commit
4077893d08
|
@ -137,6 +137,12 @@ Destination
|
||||||
Destination plugins allow you to propagate certificates managed by Lemur to additional third parties. This provides flexibility when
|
Destination plugins allow you to propagate certificates managed by Lemur to additional third parties. This provides flexibility when
|
||||||
different orchestration systems have their own way of manage certificates or there is an existing system you wish to integrate with Lemur.
|
different orchestration systems have their own way of manage certificates or there is an existing system you wish to integrate with Lemur.
|
||||||
|
|
||||||
|
By default destination plugins have a private key requirement. If your plugin does not require a certificates private key mark `requires_key = False`
|
||||||
|
in the plugins base class like so::
|
||||||
|
|
||||||
|
class MyDestinationPlugin(DestinationPlugin):
|
||||||
|
requires_key = False
|
||||||
|
|
||||||
The DestinationPlugin requires only one function to be implemented::
|
The DestinationPlugin requires only one function to be implemented::
|
||||||
|
|
||||||
def upload(self, cert, private_key, cert_chain, options, **kwargs):
|
def upload(self, cert, private_key, cert_chain, options, **kwargs):
|
||||||
|
|
|
@ -11,6 +11,7 @@ from sqlalchemy import Column, Integer, String, Text, func, ForeignKey, DateTime
|
||||||
from sqlalchemy.dialects.postgresql import JSON
|
from sqlalchemy.dialects.postgresql import JSON
|
||||||
|
|
||||||
from lemur.database import db
|
from lemur.database import db
|
||||||
|
from lemur.plugins.base import plugins
|
||||||
from lemur.models import roles_authorities
|
from lemur.models import roles_authorities
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,3 +39,7 @@ class Authority(db.Model):
|
||||||
self.description = kwargs.get('description')
|
self.description = kwargs.get('description')
|
||||||
self.authority_certificate = kwargs['authority_certificate']
|
self.authority_certificate = kwargs['authority_certificate']
|
||||||
self.plugin_name = kwargs['plugin']['slug']
|
self.plugin_name = kwargs['plugin']['slug']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def plugin(self):
|
||||||
|
return plugins.get(self.plugin_name)
|
||||||
|
|
|
@ -158,6 +158,7 @@ def update_destinations(target, value, initiator):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
destination_plugin = plugins.get(value.plugin_name)
|
destination_plugin = plugins.get(value.plugin_name)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
destination_plugin.upload(target.name, target.body, target.private_key, target.chain, value.options)
|
destination_plugin.upload(target.name, target.body, target.private_key, target.chain, value.options)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -584,6 +584,11 @@ class Certificates(AuthenticatedResource):
|
||||||
permission = CertificatePermission(cert.id, owner_role, [x.name for x in cert.roles])
|
permission = CertificatePermission(cert.id, owner_role, [x.name for x in cert.roles])
|
||||||
|
|
||||||
if permission.can():
|
if permission.can():
|
||||||
|
for destination in data['destinations']:
|
||||||
|
if destination.plugin.requires_key:
|
||||||
|
if not cert.private_key:
|
||||||
|
return dict('Unable to add destination: {0}. Certificate does not have required private key.'.format(destination.label))
|
||||||
|
|
||||||
return service.update(
|
return service.update(
|
||||||
certificate_id,
|
certificate_id,
|
||||||
data['owner'],
|
data['owner'],
|
||||||
|
@ -871,10 +876,13 @@ class CertificateExport(AuthenticatedResource):
|
||||||
plugin = data['plugin']['plugin_object']
|
plugin = data['plugin']['plugin_object']
|
||||||
|
|
||||||
if plugin.requires_key:
|
if plugin.requires_key:
|
||||||
if permission.can():
|
if cert.private_key:
|
||||||
extension, passphrase, data = plugin.export(cert.body, cert.chain, cert.private_key, options)
|
if permission.can():
|
||||||
|
extension, passphrase, data = plugin.export(cert.body, cert.chain, cert.private_key, options)
|
||||||
|
else:
|
||||||
|
return dict(message='You are not authorized to export this certificate'), 403
|
||||||
else:
|
else:
|
||||||
return dict(message='You are not authorized to export this certificate'), 403
|
return dict(message='Unable to export certificate, plugin: {0} requires a private key but no key was found.'.format(plugin.slug))
|
||||||
else:
|
else:
|
||||||
extension, passphrase, data = plugin.export(cert.body, cert.chain, cert.private_key, options)
|
extension, passphrase, data = plugin.export(cert.body, cert.chain, cert.private_key, options)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
:license: Apache, see LICENSE for more details.
|
:license: Apache, see LICENSE for more details.
|
||||||
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
||||||
"""
|
"""
|
||||||
import copy
|
|
||||||
from sqlalchemy import Column, Integer, String, Text
|
from sqlalchemy import Column, Integer, String, Text
|
||||||
from sqlalchemy_utils import JSONType
|
from sqlalchemy_utils import JSONType
|
||||||
from lemur.database import db
|
from lemur.database import db
|
||||||
|
@ -23,7 +22,4 @@ class Destination(db.Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def plugin(self):
|
def plugin(self):
|
||||||
p = plugins.get(self.plugin_name)
|
return plugins.get(self.plugin_name)
|
||||||
c = copy.deepcopy(p)
|
|
||||||
c.options = self.options
|
|
||||||
return c
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from lemur.plugins.base import Plugin
|
||||||
|
|
||||||
class DestinationPlugin(Plugin):
|
class DestinationPlugin(Plugin):
|
||||||
type = 'destination'
|
type = 'destination'
|
||||||
|
requires_key = True
|
||||||
|
|
||||||
def upload(self):
|
def upload(self):
|
||||||
raise NotImplemented
|
raise NotImplemented
|
||||||
|
|
|
@ -68,19 +68,16 @@ class AWSDestinationPlugin(DestinationPlugin):
|
||||||
# }
|
# }
|
||||||
|
|
||||||
def upload(self, name, body, private_key, cert_chain, options, **kwargs):
|
def upload(self, name, body, private_key, cert_chain, options, **kwargs):
|
||||||
if private_key:
|
try:
|
||||||
try:
|
iam.upload_cert(self.get_option('accountNumber', options), name, body, private_key,
|
||||||
iam.upload_cert(self.get_option('accountNumber', options), name, body, private_key,
|
cert_chain=cert_chain)
|
||||||
cert_chain=cert_chain)
|
except BotoServerError as e:
|
||||||
except BotoServerError as e:
|
if e.error_code != 'EntityAlreadyExists':
|
||||||
if e.error_code != 'EntityAlreadyExists':
|
raise Exception(e)
|
||||||
raise Exception(e)
|
|
||||||
|
|
||||||
e = self.get_option('elb', options)
|
e = self.get_option('elb', options)
|
||||||
if e:
|
if e:
|
||||||
attach_certificate(kwargs['accountNumber'], ['region'], e['name'], e['port'], e['certificateId'])
|
attach_certificate(kwargs['accountNumber'], ['region'], e['name'], e['port'], e['certificateId'])
|
||||||
else:
|
|
||||||
raise Exception("Unable to upload to AWS, private key is required")
|
|
||||||
|
|
||||||
|
|
||||||
class AWSSourcePlugin(SourcePlugin):
|
class AWSSourcePlugin(SourcePlugin):
|
||||||
|
|
|
@ -236,9 +236,6 @@ class JavaKeystoreExportPlugin(ExportPlugin):
|
||||||
alias = "blah"
|
alias = "blah"
|
||||||
|
|
||||||
with mktemppath() as jks_tmp:
|
with mktemppath() as jks_tmp:
|
||||||
if not key:
|
|
||||||
raise Exception("Unable to export, no private key found.")
|
|
||||||
|
|
||||||
create_keystore(body, chain, jks_tmp, key, alias, passphrase)
|
create_keystore(body, chain, jks_tmp, key, alias, passphrase)
|
||||||
|
|
||||||
with open(jks_tmp, 'rb') as f:
|
with open(jks_tmp, 'rb') as f:
|
||||||
|
|
|
@ -25,7 +25,7 @@ def test_authority_input_schema(client, role):
|
||||||
assert not errors
|
assert not errors
|
||||||
|
|
||||||
|
|
||||||
def test_user_authority(session, client, authority, role, user):
|
def test_user_authority(session, client, authority, role, user, issuer_plugin):
|
||||||
assert client.get(api.url_for(AuthoritiesList), headers=user['token']).json['total'] == 0
|
assert client.get(api.url_for(AuthoritiesList), headers=user['token']).json['total'] == 0
|
||||||
u = user['user']
|
u = user['user']
|
||||||
u.roles.append(role)
|
u.roles.append(role)
|
||||||
|
|
Loading…
Reference in New Issue