diff --git a/README.rst b/README.rst index a7cb712d..40d06db7 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,16 @@ Lemur -***** +===== -[![Build Status](https://magnum.travis-ci.com/Netflix/lemur.svg?token=i5tcyx3z4N7pEVTxTeuP&branch=master)](https://magnum.travis-ci.com/Netflix/lemur) +.. image:: https://img.shields.io/pypi/v/lemur.svg + :target: https://pypi.python.org/pypi/lemur/ + :alt: Latest Version + +.. image:: https://readthedocs.org/projects/lemur/badge/?version=latest + :target: https://lemur.readthedocs.org + :alt: Latest Docs + +.. image:: https://magnum.travis-ci.com/Netflix/lemur.svg?branch=master + :target: https://magnum.travis-ci.com/Netflix/lemur Lemur manages SSL certificate creation. It provides a central portal for developers to issuer their own SSL certificates with 'sane' defaults. diff --git a/docs/developer/index.rst b/docs/developer/index.rst index 201d1d18..12aee616 100644 --- a/docs/developer/index.rst +++ b/docs/developer/index.rst @@ -178,6 +178,7 @@ Uncertain about how to write tests? Take a look at some existing tests that are You can see a list of open pull requests (pending changes) by visiting https://github.com/netflix/lemur/pulls +Pull requests should be against **master** and pass all TravisCI checks Plugins ======= diff --git a/docs/developer/internals/lemur.accounts.rst b/docs/developer/internals/lemur.accounts.rst deleted file mode 100644 index 6191c687..00000000 --- a/docs/developer/internals/lemur.accounts.rst +++ /dev/null @@ -1,20 +0,0 @@ -accounts Package -================ - -:mod:`models` Module --------------------- - -.. automodule:: lemur.accounts.models - :members: - :undoc-members: - :show-inheritance: - -:mod:`service` Module ---------------------- - -.. automodule:: lemur.accounts.service - :members: - :undoc-members: - :show-inheritance: - - diff --git a/docs/developer/internals/lemur.analyze.rst b/docs/developer/internals/lemur.analyze.rst deleted file mode 100644 index 6f8dd07f..00000000 --- a/docs/developer/internals/lemur.analyze.rst +++ /dev/null @@ -1,11 +0,0 @@ -analyze Package -=============== - -:mod:`service` Module ---------------------- - -.. automodule:: lemur.analyze.service - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/developer/internals/lemur.auth.rst b/docs/developer/internals/lemur.auth.rst index 3538758c..5f84d19c 100644 --- a/docs/developer/internals/lemur.auth.rst +++ b/docs/developer/internals/lemur.auth.rst @@ -17,4 +17,11 @@ auth Package :undoc-members: :show-inheritance: +:mod:`views` Module +------------------- + +.. automodule:: lemur.auth.views + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/developer/internals/lemur.authorities.rst b/docs/developer/internals/lemur.authorities.rst index 925d33c3..a274642c 100644 --- a/docs/developer/internals/lemur.authorities.rst +++ b/docs/developer/internals/lemur.authorities.rst @@ -17,4 +17,11 @@ authorities Package :undoc-members: :show-inheritance: +:mod:`views` Module +------------------- + +.. automodule:: lemur.authorities.views + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/developer/internals/lemur.certificates.rst b/docs/developer/internals/lemur.certificates.rst index a7b9f5c0..a19617c4 100644 --- a/docs/developer/internals/lemur.certificates.rst +++ b/docs/developer/internals/lemur.certificates.rst @@ -5,6 +5,7 @@ certificates Package ------------------------ .. automodule:: lemur.certificates.exceptions + :noindex: :members: :undoc-members: :show-inheritance: @@ -13,6 +14,7 @@ certificates Package -------------------- .. automodule:: lemur.certificates.models + :noindex: :members: :undoc-members: :show-inheritance: @@ -21,6 +23,7 @@ certificates Package --------------------- .. automodule:: lemur.certificates.service + :noindex: :members: :undoc-members: :show-inheritance: @@ -29,6 +32,7 @@ certificates Package ------------------ .. automodule:: lemur.certificates.sync + :noindex: :members: :undoc-members: :show-inheritance: @@ -37,7 +41,16 @@ certificates Package -------------------- .. automodule:: lemur.certificates.verify + :noindex: :members: :undoc-members: :show-inheritance: +:mod:`views` Module +------------------- + +.. automodule:: lemur.certificates.views + :noindex: + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/developer/internals/lemur.common.rst b/docs/developer/internals/lemur.common.rst index ec03c39d..45102cd8 100644 --- a/docs/developer/internals/lemur.common.rst +++ b/docs/developer/internals/lemur.common.rst @@ -1,14 +1,6 @@ common Package ============== -:mod:`crypto` Module --------------------- - -.. automodule:: lemur.common.crypto - :members: - :undoc-members: - :show-inheritance: - :mod:`health` Module -------------------- @@ -17,6 +9,14 @@ common Package :undoc-members: :show-inheritance: +:mod:`managers` Module +---------------------- + +.. automodule:: lemur.common.managers + :members: + :undoc-members: + :show-inheritance: + :mod:`utils` Module ------------------- @@ -25,10 +25,3 @@ common Package :undoc-members: :show-inheritance: -Subpackages ------------ - -.. toctree:: - - lemur.common.services - diff --git a/docs/developer/internals/lemur.common.services.aws.rst b/docs/developer/internals/lemur.common.services.aws.rst deleted file mode 100644 index 9d95dd1d..00000000 --- a/docs/developer/internals/lemur.common.services.aws.rst +++ /dev/null @@ -1,35 +0,0 @@ -aws Package -=========== - -:mod:`elb` Module ------------------ - -.. automodule:: lemur.common.services.aws.elb - :members: - :undoc-members: - :show-inheritance: - -:mod:`iam` Module ------------------ - -.. automodule:: lemur.common.services.aws.iam - :members: - :undoc-members: - :show-inheritance: - -:mod:`ses` Module ------------------ - -.. automodule:: lemur.common.services.aws.ses - :members: - :undoc-members: - :show-inheritance: - -:mod:`sts` Module ------------------ - -.. automodule:: lemur.common.services.aws.sts - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/developer/internals/lemur.common.services.issuers.plugins.cloudca.rst b/docs/developer/internals/lemur.common.services.issuers.plugins.cloudca.rst deleted file mode 100644 index 44ced49c..00000000 --- a/docs/developer/internals/lemur.common.services.issuers.plugins.cloudca.rst +++ /dev/null @@ -1,19 +0,0 @@ -cloudca Package -=============== - -:mod:`cloudca` Module ---------------------- - -.. automodule:: lemur.common.services.issuers.plugins.cloudca.cloudca - :members: - :undoc-members: - :show-inheritance: - -:mod:`constants` Module ------------------------ - -.. automodule:: lemur.common.services.issuers.plugins.cloudca.constants - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/developer/internals/lemur.common.services.issuers.plugins.rst b/docs/developer/internals/lemur.common.services.issuers.plugins.rst deleted file mode 100644 index 18010965..00000000 --- a/docs/developer/internals/lemur.common.services.issuers.plugins.rst +++ /dev/null @@ -1,11 +0,0 @@ -plugins Package -=============== - -Subpackages ------------ - -.. toctree:: - - lemur.common.services.issuers.plugins.cloudca - lemur.common.services.issuers.plugins.verisign - diff --git a/docs/developer/internals/lemur.common.services.issuers.plugins.verisign.rst b/docs/developer/internals/lemur.common.services.issuers.plugins.verisign.rst deleted file mode 100644 index 23e56719..00000000 --- a/docs/developer/internals/lemur.common.services.issuers.plugins.verisign.rst +++ /dev/null @@ -1,19 +0,0 @@ -verisign Package -================ - -:mod:`constants` Module ------------------------ - -.. automodule:: lemur.common.services.issuers.plugins.verisign.constants - :members: - :undoc-members: - :show-inheritance: - -:mod:`verisign` Module ----------------------- - -.. automodule:: lemur.common.services.issuers.plugins.verisign.verisign - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/developer/internals/lemur.common.services.issuers.rst b/docs/developer/internals/lemur.common.services.issuers.rst deleted file mode 100644 index 331c5a95..00000000 --- a/docs/developer/internals/lemur.common.services.issuers.rst +++ /dev/null @@ -1,26 +0,0 @@ -issuers Package -=============== - -:mod:`issuer` Module --------------------- - -.. automodule:: lemur.common.services.issuers.issuer - :members: - :undoc-members: - :show-inheritance: - -:mod:`manager` Module ---------------------- - -.. automodule:: lemur.common.services.issuers.manager - :members: - :undoc-members: - :show-inheritance: - -Subpackages ------------ - -.. toctree:: - - lemur.common.services.issuers.plugins - diff --git a/docs/developer/internals/lemur.common.services.rst b/docs/developer/internals/lemur.common.services.rst deleted file mode 100644 index 6ef59523..00000000 --- a/docs/developer/internals/lemur.common.services.rst +++ /dev/null @@ -1,11 +0,0 @@ -services Package -================ - -Subpackages ------------ - -.. toctree:: - - lemur.common.services.aws - lemur.common.services.issuers - diff --git a/docs/developer/internals/lemur.domains.rst b/docs/developer/internals/lemur.domains.rst index e728a053..ca798498 100644 --- a/docs/developer/internals/lemur.domains.rst +++ b/docs/developer/internals/lemur.domains.rst @@ -17,3 +17,11 @@ domains Package :undoc-members: :show-inheritance: +:mod:`views` Module +------------------- + +.. automodule:: lemur.domains.views + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/developer/internals/lemur.elbs.rst b/docs/developer/internals/lemur.elbs.rst deleted file mode 100644 index 74786ed6..00000000 --- a/docs/developer/internals/lemur.elbs.rst +++ /dev/null @@ -1,35 +0,0 @@ -elbs Package -============ - -:mod:`models` Module --------------------- - -.. automodule:: lemur.elbs.models - :members: - :undoc-members: - :show-inheritance: - -:mod:`service` Module ---------------------- - -.. automodule:: lemur.elbs.service - :members: - :undoc-members: - :show-inheritance: - -:mod:`sync` Module ------------------- - -.. automodule:: lemur.elbs.sync - :members: - :undoc-members: - :show-inheritance: - -:mod:`views` Module -------------------- - -.. automodule:: lemur.elbs.views - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/developer/internals/lemur.listeners.rst b/docs/developer/internals/lemur.listeners.rst deleted file mode 100644 index 4ef98588..00000000 --- a/docs/developer/internals/lemur.listeners.rst +++ /dev/null @@ -1,27 +0,0 @@ -listeners Package -================= - -:mod:`models` Module --------------------- - -.. automodule:: lemur.listeners.models - :members: - :undoc-members: - :show-inheritance: - -:mod:`service` Module ---------------------- - -.. automodule:: lemur.listeners.service - :members: - :undoc-members: - :show-inheritance: - -:mod:`views` Module -------------------- - -.. automodule:: lemur.listeners.views - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/developer/internals/lemur.roles.rst b/docs/developer/internals/lemur.roles.rst index bb60e23c..80777e52 100644 --- a/docs/developer/internals/lemur.roles.rst +++ b/docs/developer/internals/lemur.roles.rst @@ -17,4 +17,10 @@ roles Package :undoc-members: :show-inheritance: +:mod:`views` Module +------------------- +.. automodule:: lemur.roles.views + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/developer/internals/lemur.rst b/docs/developer/internals/lemur.rst index 6d7e64bf..eb6f225e 100644 --- a/docs/developer/internals/lemur.rst +++ b/docs/developer/internals/lemur.rst @@ -1,7 +1,20 @@ +lemur Package +============= + +:mod:`lemur` Package +-------------------- + +.. automodule:: lemur.__init__ + :noindex: + :members: + :undoc-members: + :show-inheritance: + :mod:`constants` Module ----------------------- .. automodule:: lemur.constants + :noindex: :members: :undoc-members: :show-inheritance: @@ -10,6 +23,7 @@ ---------------------- .. automodule:: lemur.database + :noindex: :members: :undoc-members: :show-inheritance: @@ -18,6 +32,7 @@ ------------------------ .. automodule:: lemur.decorators + :noindex: :members: :undoc-members: :show-inheritance: @@ -26,6 +41,7 @@ ------------------------ .. automodule:: lemur.exceptions + :noindex: :members: :undoc-members: :show-inheritance: @@ -34,6 +50,7 @@ ------------------------ .. automodule:: lemur.extensions + :noindex: :members: :undoc-members: :show-inheritance: @@ -42,6 +59,7 @@ --------------------- .. automodule:: lemur.factory + :noindex: :members: :undoc-members: :show-inheritance: @@ -50,6 +68,7 @@ -------------------- .. automodule:: lemur.manage + :noindex: :members: :undoc-members: :show-inheritance: @@ -58,14 +77,7 @@ -------------------- .. automodule:: lemur.models - :members: - :undoc-members: - :show-inheritance: - -:mod:`notifications` Module ---------------------------- - -.. automodule:: lemur.notifications + :noindex: :members: :undoc-members: :show-inheritance: @@ -75,13 +87,14 @@ Subpackages .. toctree:: - lemur.accounts lemur.auth lemur.authorities lemur.certificates lemur.common + lemur.destinations lemur.domains + lemur.notifications + lemur.plugins lemur.roles lemur.status lemur.users - diff --git a/docs/developer/internals/lemur.users.rst b/docs/developer/internals/lemur.users.rst index 3039ef00..9ce84ad3 100644 --- a/docs/developer/internals/lemur.users.rst +++ b/docs/developer/internals/lemur.users.rst @@ -17,3 +17,11 @@ users Package :undoc-members: :show-inheritance: +:mod:`views` Module +------------------- + +.. automodule:: lemur.users.views + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/developer/plugins/index.rst b/docs/developer/plugins/index.rst index 3168c21e..329a5a1b 100644 --- a/docs/developer/plugins/index.rst +++ b/docs/developer/plugins/index.rst @@ -6,6 +6,11 @@ Several interfaces exist for extending Lemur: * Issuer (lemur.plugins.base.issuer) * Destination (lemur.plugins.base.destination) * Source (lemur.plugins.base.source) +* Notification (lemur.plugins.base.notification) + +Each interface has its own function that will need to be defined in order for +your plugin to work correctly. See :ref:`Plugin Interfaces ` for details. + Structure --------- @@ -54,44 +59,173 @@ And you'll register it via ``entry_points`` in your ``setup.py``:: }, ) +You can potentially package multiple plugin types in one package, say you want to create a source and +destination plugins for the same third-party. To accomplish this simply alias the plugin in entry points to point +at multiple plugins within your package:: + + setup( + # ... + entry_points={ + 'lemur.plugins': [ + 'pluginnamesource = lemur_pluginname.plugin:PluginNameSource', + 'pluginnamedestination = lemur_pluginname.plugin:PluginNameDestination' + ], + }, + ) That's it! Users will be able to install your plugin via ``pip install ``. -Interfaces -========== +.. _PluginInterfaces: -Lemur has several different plugin interfaces that are used to extend Lemur, each of them require -that you subclass and override their functions in order for your plugin to function. +Plugin Interfaces +================= +In order to use the interfaces all plugins are required to inherit and override unimplemented functions +of the parent object. Issuer ------ -Issuer plugins are to be used when you want to allow Lemur to use external services to create certificates. -In the simple case this means that you have one Certificate Authority and you ask it for certificates given a -few parameters. In a more advanced case this could mean that this third party not only allows you to create certifcates -but also allows you to create Certificate Authorities and Sub Certificate Authorities. +Issuer plugins are used when you have an external service that creates certificates or authorities. +In the simple case the third party only issues certificates (Verisign, DigiCert, etc.). -The `IssuerPlugin` interface only required that you implement one function:: +If you have a third party or internal service that creates authorities (CloudCA, EJBCA, etc.), Lemur has you covered, +it can treat any issuer plugin as both a source of creating new certificates as well as new authorities. + + +The `IssuerPlugin` exposes two functions:: def create_certificate(self, options): # requests.get('a third party') +Lemur will pass a dictionary of all possible options for certificate creation. Including a valid CSR, and the raw options associated with the request. -Lemur will pass a dictionary of all possible options for certificate creation. - -Optionally the `IssuerPlugin` exposes another function for authority create:: +If you wish to be able to create new authorities implement the following function and ensure that the ROOT_CERTIFICATE and the INTERMEDIATE_CERTIFICATE (if any) for the new authority is returned:: def create_authority(self, options): - # request.get('a third party') + root_cert, intermediate_cert, username, password = request.get('a third party') + + # if your provider creates specific credentials for each authority you can associated them with the role associated with the authority + # these credentials will be provided along with any other options when a certificate is created + role = dict(username=username, password=password, name='generatedAuthority') + return root_cert, intermediate_cert, [role] -If implemented this function will be used to allow users to create external Certificate Authorities. From this function -you are expected to return the ROOT certificate authority, any intermediates that Authority might provide and any roles -you wish to be associated with this authority. +.. Note:: + Lemur uses PEM (PKCS#7) certificates as it's internal standard, if you recieve certificates in other formats convert them to PEM before returning. -.. Note:: You do not need to associate roles to the authority at creation time as they can always be associated after the -fact. + +If instead you do not need need to generate authorities but instead use a static authority (Verisign, DigiCert), you can use publicly available constants:: + + + def create_authority(self, options): + # optionally associate a role with authority to control who can use it + role = dict(username='', password='', name='exampleAuthority') + # username and password don't really matter here because we do no need to authenticate our authority against a third party + return EXAMPLE_ROOT_CERTIFICATE, EXAMPLE_INTERMEDIATE_CERTIFICATE, [role] + + +.. Note:: You do not need to associate roles to the authority at creation time as they can always be associated after the fact. + + +The `IssuerPlugin` doesn't have any options like Destination, Source, and Notification plugins. Essentially Lemur **should** already have +any fields you might need to submit a request to a third party. If there are additional options you need +in your plugin feel free to open an issue, or look into adding additional options to issuers yourself. + +Destination +----------- + +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. + +The DestinationPlugin requires only one function to be implemented:: + + def upload(self, cert, private_key, cert_chain, options, **kwargs): + # request.post('a third party') + +Additionally the DestinationPlugin allows the plugin author to add additional options +that can be used to help define sub-destinations. + +For example, if we look at the aws-destination plugin we can see that it defines an `accountNumber` option:: + + options = [ + { + 'name': 'accountNumber', + 'type': 'int', + 'required': True, + 'validation': '/^[0-9]{12,12}$/', + 'helpMessage': 'Must be a valid AWS account number!', + } + ] + +By defining an `accountNumber` we can make this plugin handle many N number of AWS accounts instead of just one. + +The schema for defining plugin options are pretty straightforward: + + - **Name**: name of the variable you wish to present the user, snake case (snakeCase) is preferrred as Lemur + will parse these and create pretty variable titles + - **Type** there are currently four supported variable types + - **Int** creates an html integer box for the user to enter integers into + - **Str** creates a html text input box + - **Boolean** creates a checkbox for the user to signify truithyness + - **Select** creates a select box that gives the user a list of options + - When used a `available` key must be provided with a list of selectable options + - **Required** determines if this option is required, this **must be a boolean value** + - **Validation** simple JavaScript regular expression used to give the user an indication if the input value is valid + - **HelpMessage** simple string that provides more detail about the option + +.. Note:: + DestinationPlugin, NotificationPlugin and SourcePlugin all support the option + schema outlined above. + + +Notification +------------ + +Lemur includes the ability to create Email notifications by **default**. These notifications +currently come in the form of expiration noticies. Lemur periodically checks certifications expiration dates and +determines if a given certificate is eligible for notification. There are currently only two parameters used to +determine if a certificate is eligible; validity expiration (date the certificate is no longer valid) and the number +of days the current date (UTC) is from that expiration date. + +There are currently two objects that available for notification plugins the first is `NotficationPlugin`. This is the base object for +any notification within Lemur. Currently the only support notification type is an certificate expiration notification. If you +are trying to create a new notification type (audit, failed logins, etc.) this would be the object to base your plugin on. +You would also then need to build additional code to trigger the new notification type. + +The second is `ExpirationNotificationPlugin`, this object inherits from `NotificationPlugin` object. +You will most likely want to base your plugin on, if you want to add new channels for expiration notices (Slack, Hipcat, Jira, etc.). It adds default options that are required by +by all expiration notifications (interval, unit). This interface expects for the child to define the following function:: + + def send(self): + # request.post("some alerting infrastructure") + + +Source +------ + +When building Lemur we realized that although it would be nice if every certificate went through Lemur to get issued, but this is not +always be the case. Often times there are third parties that will issue certificates on your behalf and these can get deployed +to infrastructure without any interaction with Lemur. In an attempt to combat this and try to track every certificate, Lemur has a notion of +certificate **Sources**. Lemur will contact the source at periodic intervals and attempt to **sync** against the source. This means downloading or discovering any +certificate Lemur does not know about and adding the certificate to it's inventory to be tracked and alerted on. + +The `SourcePlugin` object has one default option of `pollRate`. This controls the number of seconds which to get new certificates. + + .. warning:: + Lemur currently has a very basic polling system of running a cron job every 15min to see which source plugins need to be run. + This means special consideration needs to be taken such that running all `SourcePlugins` does not take >15min to run. It also means + that the minimum resolution of a source plugin poll rate is effectively 15min. + + +The `SourcePlugin` object requires implementation of one function:: + + def get_certificates(self, **kwargs): + # request.get("some source of certificates") + + +.. Note:: + Often times to facilitate code re-use it makes sense put source and destination plugins into one package. Testing @@ -165,5 +299,4 @@ Running tests follows the py.test standard. As long as your test files and metho =========================== 1 passed in 0.35 seconds ============================ -.. SeeAlso:: Lemur bundles several plugins that use the same interfaces mentioned above. View the source: #TODO - +.. SeeAlso:: Lemur bundles several plugins that use the same interfaces mentioned above. View the source: # TODO diff --git a/docs/developer/rest.rst b/docs/developer/rest.rst index 63b1cf0d..e4619385 100644 --- a/docs/developer/rest.rst +++ b/docs/developer/rest.rst @@ -9,10 +9,18 @@ Authentication :undoc-members: :show-inheritance: -Accounts --------- +Destinations +------------ -.. automodule:: lemur.accounts.views +.. automodule:: lemur.destinations.views + :members: + :undoc-members: + :show-inheritance: + +Notifications +------------- + +.. automodule:: lemur.notifications.views :members: :undoc-members: :show-inheritance: @@ -56,5 +64,3 @@ Domains :members: :undoc-members: :show-inheritance: - - diff --git a/docs/generate_api.py b/docs/generate_api.py new file mode 100644 index 00000000..c1a02a38 --- /dev/null +++ b/docs/generate_api.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +sphinx-autopackage-script + +This script parses a directory tree looking for python modules and packages and +creates ReST files appropriately to create code documentation with Sphinx. +It also creates a modules index (named modules.). +""" + +# Copyright 2008 Société des arts technologiques (SAT), http://www.sat.qc.ca/ +# Copyright 2010 Thomas Waldmann +# All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import os +import optparse + + +# automodule options +OPTIONS = ['members', + 'undoc-members', + # 'inherited-members', # disabled because there's a bug in sphinx + 'show-inheritance', + ] + +INIT = '__init__.py' + +def makename(package, module): + """Join package and module with a dot.""" + # Both package and module can be None/empty. + if package: + name = package + if module: + name += '.' + module + else: + name = module + return name + +def write_file(name, text, opts): + """Write the output file for module/package .""" + if opts.dryrun: + return + fname = os.path.join(opts.destdir, "%s.%s" % (name, opts.suffix)) + if not opts.force and os.path.isfile(fname): + print 'File %s already exists, skipping.' % fname + else: + print 'Creating file %s.' % fname + f = open(fname, 'w') + f.write(text) + f.close() + +def format_heading(level, text): + """Create a heading of [1, 2 or 3 supported].""" + underlining = ['=', '-', '~', ][level-1] * len(text) + return '%s\n%s\n\n' % (text, underlining) + +def format_directive(module, package=None): + """Create the automodule directive and add the options.""" + directive = '.. automodule:: %s\n' % makename(package, module) + for option in OPTIONS: + directive += ' :%s:\n' % option + return directive + +def create_module_file(package, module, opts): + """Build the text of the file and write the file.""" + text = format_heading(1, '%s Module' % module) + text += format_heading(2, ':mod:`%s` Module' % module) + text += format_directive(module, package) + write_file(makename(package, module), text, opts) + +def create_package_file(root, master_package, subroot, py_files, opts, subs): + """Build the text of the file and write the file.""" + package = os.path.split(root)[-1] + text = format_heading(1, '%s Package' % package) + # add each package's module + for py_file in py_files: + if shall_skip(os.path.join(root, py_file)): + continue + is_package = py_file == INIT + py_file = os.path.splitext(py_file)[0] + py_path = makename(subroot, py_file) + if is_package: + heading = ':mod:`%s` Package' % package + else: + heading = ':mod:`%s` Module' % py_file + text += format_heading(2, heading) + text += format_directive(is_package and subroot or py_path, master_package) + text += '\n' + + # build a list of directories that are packages (they contain an INIT file) + subs = [sub for sub in subs if os.path.isfile(os.path.join(root, sub, INIT))] + # if there are some package directories, add a TOC for theses subpackages + if subs: + text += format_heading(2, 'Subpackages') + text += '.. toctree::\n\n' + for sub in subs: + text += ' %s.%s\n' % (makename(master_package, subroot), sub) + text += '\n' + + write_file(makename(master_package, subroot), text, opts) + +def create_modules_toc_file(master_package, modules, opts, name='modules'): + """ + Create the module's index. + """ + text = format_heading(1, '%s Modules' % opts.header) + text += '.. toctree::\n' + text += ' :maxdepth: %s\n\n' % opts.maxdepth + + modules.sort() + prev_module = '' + for module in modules: + # look if the module is a subpackage and, if yes, ignore it + if module.startswith(prev_module + '.'): + continue + prev_module = module + text += ' %s\n' % module + + write_file(name, text, opts) + +def shall_skip(module): + """ + Check if we want to skip this module. + """ + # skip it, if there is nothing (or just \n or \r\n) in the file + return os.path.getsize(module) < 3 + +def recurse_tree(path, excludes, opts): + """ + Look for every file in the directory tree and create the corresponding + ReST files. + """ + # use absolute path for root, as relative paths like '../../foo' cause + # 'if "/." in root ...' to filter out *all* modules otherwise + path = os.path.abspath(path) + # check if the base directory is a package and get is name + if INIT in os.listdir(path): + package_name = path.split(os.path.sep)[-1] + else: + package_name = None + + toc = [] + tree = os.walk(path, False) + for root, subs, files in tree: + # keep only the Python script files + py_files = sorted([f for f in files if os.path.splitext(f)[1] == '.py']) + if INIT in py_files: + py_files.remove(INIT) + py_files.insert(0, INIT) + # remove hidden ('.') and private ('_') directories + subs = sorted([sub for sub in subs if sub[0] not in ['.', '_']]) + # check if there are valid files to process + # TODO: could add check for windows hidden files + if "/." in root or "/_" in root \ + or not py_files \ + or is_excluded(root, excludes): + continue + if INIT in py_files: + # we are in package ... + if (# ... with subpackage(s) + subs + or + # ... with some module(s) + len(py_files) > 1 + or + # ... with a not-to-be-skipped INIT file + not shall_skip(os.path.join(root, INIT)) + ): + subroot = root[len(path):].lstrip(os.path.sep).replace(os.path.sep, '.') + create_package_file(root, package_name, subroot, py_files, opts, subs) + toc.append(makename(package_name, subroot)) + elif root == path: + # if we are at the root level, we don't require it to be a package + for py_file in py_files: + if not shall_skip(os.path.join(path, py_file)): + module = os.path.splitext(py_file)[0] + create_module_file(package_name, module, opts) + toc.append(makename(package_name, module)) + + # create the module's index + if not opts.notoc: + create_modules_toc_file(package_name, toc, opts) + +def normalize_excludes(rootpath, excludes): + """ + Normalize the excluded directory list: + * must be either an absolute path or start with rootpath, + * otherwise it is joined with rootpath + * with trailing slash + """ + sep = os.path.sep + f_excludes = [] + for exclude in excludes: + if not os.path.isabs(exclude) and not exclude.startswith(rootpath): + exclude = os.path.join(rootpath, exclude) + if not exclude.endswith(sep): + exclude += sep + f_excludes.append(exclude) + return f_excludes + +def is_excluded(root, excludes): + """ + Check if the directory is in the exclude list. + + Note: by having trailing slashes, we avoid common prefix issues, like + e.g. an exlude "foo" also accidentally excluding "foobar". + """ + sep = os.path.sep + if not root.endswith(sep): + root += sep + for exclude in excludes: + if root.startswith(exclude): + return True + return False + +def main(): + """ + Parse and check the command line arguments. + """ + parser = optparse.OptionParser(usage="""usage: %prog [options] [exclude paths, ...] + +Note: By default this script will not overwrite already created files.""") + parser.add_option("-n", "--doc-header", action="store", dest="header", help="Documentation Header (default=Project)", default="Project") + parser.add_option("-d", "--dest-dir", action="store", dest="destdir", help="Output destination directory", default="") + parser.add_option("-s", "--suffix", action="store", dest="suffix", help="module suffix (default=txt)", default="txt") + parser.add_option("-m", "--maxdepth", action="store", dest="maxdepth", help="Maximum depth of submodules to show in the TOC (default=4)", type="int", default=4) + parser.add_option("-r", "--dry-run", action="store_true", dest="dryrun", help="Run the script without creating the files") + parser.add_option("-f", "--force", action="store_true", dest="force", help="Overwrite all the files") + parser.add_option("-t", "--no-toc", action="store_true", dest="notoc", help="Don't create the table of content file") + (opts, args) = parser.parse_args() + if not args: + parser.error("package path is required.") + else: + rootpath, excludes = args[0], args[1:] + if os.path.isdir(rootpath): + # check if the output destination is a valid directory + if opts.destdir and os.path.isdir(opts.destdir): + excludes = normalize_excludes(rootpath, excludes) + recurse_tree(rootpath, excludes, opts) + else: + print '%s is not a valid output destination directory.' % opts.destdir + else: + print '%s is not a valid directory.' % rootpath + + +if __name__ == '__main__': + main() diff --git a/docs/guide/index.rst b/docs/guide/index.rst index 1564897b..542e1733 100644 --- a/docs/guide/index.rst +++ b/docs/guide/index.rst @@ -1,10 +1,14 @@ -Creating Certificates -===================== - - Creating Users ============== Creating Roles -============== \ No newline at end of file +============== + + +Creating Authorities +==================== + + +Creating Certificates +===================== diff --git a/docs/production/index.rst b/docs/production/index.rst index 0e4829bd..fb62cde7 100644 --- a/docs/production/index.rst +++ b/docs/production/index.rst @@ -64,17 +64,6 @@ You will benefit from having: You must create a Nginx configuration file for Lemur. On GNU/Linux, they usually go into /etc/nginx/conf.d/. Name it lemur.conf. -The minimal configuration file to run the site is:: - - server { - listen 80; - server_name www.yourwebsite.com; - - location / { - proxy_pass http://127.0.0.1:5000; - } - } - `proxy_pass` just passes the external request to the Python process. The port much match the one used by the 0bin process of course. @@ -106,7 +95,7 @@ You can make some adjustments to get a better user experience:: } location / { - root /www/lemur/lemur/static/dist; + root /path/to/lemur/static/dist; include mime.types; index index.html; } @@ -172,7 +161,7 @@ sensitive nature of Lemur and what it controls makes this essential. This is a s } location / { - root /www/lemur/lemur/static/dist; + root /path/to/lemur/static/dist; include mime.types; index index.html; } @@ -180,6 +169,8 @@ sensitive nature of Lemur and what it controls makes this essential. This is a s } +.. Note:: Some paths will have to be adjusted based on where you have choose to install Lemur. + Apache ------ diff --git a/docs/quickstart/index.rst b/docs/quickstart/index.rst index 97da5a49..f3a04a63 100644 --- a/docs/quickstart/index.rst +++ b/docs/quickstart/index.rst @@ -2,6 +2,7 @@ Quickstart ********** This guide will step you through setting up a Python-based virtualenv, installing the required packages, and configuring the basic web service. +This guide assumes a clean Ubuntu 14.04 instance, commands may differ based on the OS and configuration being used. Dependencies ------------ @@ -38,6 +39,20 @@ Finally, activate your virtualenv:: install into the virtualenv by default. +Installing build dependencies +----------------------------- + +If installing Lemur on true bare Ubuntu OS you will need to grab the following packages so that Lemur can correctly build it's +dependencies. + + $ sudo apt-get update + $ sudo apt-get install nodejs-legacy python-pip libpq-dev python-dev build-essential libssl-dev libffi-dev nginx git supervisor + +And optionally if your database is going to be on the same host as the webserver. + + $ sudo apt-get install postgres + + Installing Lemur ---------------- @@ -89,9 +104,34 @@ You can specify `-c` or `--config` to any Lemur command to specify the current e you are working in. Lemur will also look under the environmental variable `LEMUR_CONF` should that be easier to setup in your environment. +Update your configuration +------------------------- + Once created you will need to update the configuration file with information about your environment, such as which database to talk to, where keys are stores etc.. +.. Note:: If you are unVfamiliar with with the SQLALCHEMY_DATABASE_URI string it can be broken up like so: + postgresql://userame:password@databasefqdn:databaseport/databasename + +Setup Postgres +-------------- + +For production a dedicated database is recommended, for this guide we will assume postgres has been installed and is on +the same machine that Lemur is installed on. + +First, set a password for the postgres user. For this guide, we will use **lemur** as an example but you should use the database password generated for by Lemur.:: + + $ sudo -u postgres psql postgres + # \password postgres + Enter new password: lemur + Enter it again: lemur + +Type CTRL-D to exit psql once you have changed the password. + +Next, we will create our a new database:: + + $ sudo -u postgres createdb lemur + .. _InitializingLemur: Initializing Lemur @@ -102,6 +142,8 @@ used by Lemur to help associate certificates that do not currently have an owner Lemur has discovered certificates from a third party resource. This is also a default user that can be used to administer Lemur. +**Make note of the password used as this will be use to first login to the Lemur UI** + .. code-block:: bash $ lemur db init @@ -115,12 +157,6 @@ administer Lemur. for them or be enrolled automatically through SSO. This can be done through the CLI or UI. See :ref:`Creating Users ` and :ref:`Command Line Interface ` for details -.. note:: - This assumes you have already created a postgres database and have specified the right postgres URI in the - lemur configuration. See the `Postgres Documentation `_ - for details. - - Setup a Reverse Proxy --------------------- @@ -208,7 +244,7 @@ of Lemur, but we do our best to reconcile those changes. .. code-block:: bash $ crontab -e - * 3 * * * lemur sync + * 3 * * * lemur sync --all * 3 * * * lemur check_revoked Additional Utilities @@ -238,4 +274,3 @@ The above gets you going, but for production there are several different securit remember Lemur is handling sensitive data and security is imperative. See :doc:`../production/index` for more details on how to configure Lemur for production. - diff --git a/lemur/plugins/bases/source.py b/lemur/plugins/bases/source.py index 9ddae1a0..f4c6e77f 100644 --- a/lemur/plugins/bases/source.py +++ b/lemur/plugins/bases/source.py @@ -12,8 +12,19 @@ from lemur.plugins.base import Plugin class SourcePlugin(Plugin): type = 'source' + default_options = [ + { + 'name': 'pollRate', + 'type': 'int', + 'required': False, + 'helpMessage': 'Rate in seconds to poll source for new information.', + 'default': '60', + } + ] + def get_certificates(self): raise NotImplemented - def get_options(self): - return {} + @property + def options(self): + return list(self.default_options) + self.additional_options diff --git a/lemur/plugins/lemur_aws/plugin.py b/lemur/plugins/lemur_aws/plugin.py index 668e8975..07b1f9a7 100644 --- a/lemur/plugins/lemur_aws/plugin.py +++ b/lemur/plugins/lemur_aws/plugin.py @@ -66,13 +66,6 @@ class AWSSourcePlugin(SourcePlugin): 'validation': '/^[0-9]{12,12}$/', 'helpMessage': 'Must be a valid AWS account number!', }, - { - 'name': 'pollRate', - 'type': 'int', - 'required': False, - 'helpMessage': 'Rate in seconds to poll source for new information.', - 'default': '60', - } ] def get_certificates(self, **kwargs):