initial commit

This commit is contained in:
Kevin Glisson
2015-06-22 13:47:27 -07:00
commit 4330ac9c05
228 changed files with 16656 additions and 0 deletions

177
docs/Makefile Normal file
View File

@ -0,0 +1,177 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/lemur.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/lemur.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/lemur"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/lemur"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

View File

@ -0,0 +1,540 @@
Configuration
=============
.. warning::
There are many secrets that Lemur uses that must be protected. All of these options are set via the Lemur configruation
file. It is highly advised that you do not store your secrets in this file! Lemur provides functions
that allow you to encrypt files at rest and decrypt them when it's time for deployment. See :ref:`Credential Management <CredentialManagement>`
for more information.
Basic Configuration
-------------------
.. data:: LOG_LEVEL
:noindex:
::
LOG_LEVEL = "DEBUG"
.. data:: LOG_FILE
:noindex:
::
LOG_FILE = "/logs/lemur/lemur-test.log"
.. data:: debug
:noindex:
Sets the flask debug flag to true (if supported by the webserver)
::
debug = False
.. warning::
This should never be used in a production environment as it exposes Lemur to
remote code execution through the debug console.
.. data:: CORS
:noindex:
Allows for cross domain requests, this is most commonly used for development but could
be use in production if you decided to host the webUI on a different domain than the server.
Use this cautiously, if you're not sure. Set it to `False`
::
CORS = False
.. data:: SQLACHEMY_DATABASE_URI
:noindex:
If you have ever used sqlalchemy before this is the standard connection string used. Lemur uses a postgres database and the connection string would look something like:
::
SQLALCHEMY_DATABASE_URI = 'postgresql://<user>:<password>@<hostname>:5432/lemur'
.. data:: LEMUR_MAIL
:noindex:
Lemur mail service
::
LEMUR_MAIL = 'lemur.example.com'
.. data:: LEMUR_SECURITY_TEAM_EMAIL
:noindex:
This is an email or list of emails that should be notified when a certificate is expiring. It is also the contact email address for any discovered certificate.
::
LEMUR_SECURITY_TEAM_EMAIL = ['security@example.com']
.. data:: LEMUR_RESTRICTED_DOMAINS
:noindex:
This allows the administrator to mark a subset of domains or domains matching a particular regex as
*restricted*. This means that only an administrator is allows to issue the domains in question.
.. data:: LEMUR_TOKEN_SECRET
:noindex:
The TOKEN_SECRET is the secret used to create JWT tokens that are given out to users. This should be securely generated and be kept private.
See `SECRET_KEY` for methods on secure secret generation.
::
LEMUR_TOKEN_SECRET = 'supersecret'
An example of how you might generate a random string:
>>> import random
>>> secret_key = ''.join(random.choice(string.ascii_uppercase) for x in range(6))
>>> secret_key = secret_key + ''.join(random.choice("~!@#$%^&*()_+") for x in range(6))
>>> secret_key = secret_key + ''.join(random.choice(string.ascii_lowercase) for x in range(6))
>>> secret_key = secret_key + ''.join(random.choice(string.digits) for x in range(6))
.. data:: LEMUR_ENCRYPTION_KEY
:noindex:
The LEMUR_ENCRYPTION_KEY is used to encrypt data at rest within Lemur's database. Without this key Lemur will refuse
to start.
See `LEMUR_TOKEN_SECRET` for methods of secure secret generation.
::
LEMUR_ENCRYPTION_KEY = 'supersupersecret'
Authority Options
-----------------
Authorities will each have their own configuration options. There are currently two plugins bundled with Lemur,
Verisign/Symantec and CloudCA
.. data:: VERISIGN_URL
:noindex:
This is the url for the verisign API
.. data:: VERISIGN_PEM_PATH
:noindex:
This is the path to the mutual SSL certificate used for communicating with Verisign
.. data:: CLOUDCA_URL
:noindex:
This is the URL for CLoudCA API
.. data:: CLOUDCA_PEM_PATH
:noindex:
This is the path to the mutual SSL Certificate use for communicating with CLOUDCA
.. data:: CLOUDCA_BUNDLE
:noindex:
This is the path to the CLOUDCA certificate bundle
Authentication
--------------
Lemur currently supports Basic Authentication and Ping OAuth2, additional flows can be added relatively easily
If you are not using PING you do not need to configure any of these options
.. data:: PING_SECRET
:noindex:
::
PING_SECRET = 'somethingsecret'
.. data:: PING_ACCESS_TOKEN_URL
:noindex:
::
PING_ACCESS_TOKEN_URL = "https://<yourpingserver>/as/token.oauth2"
.. data:: PING_USER_API_URL
:noindex:
::
PING_USER_API_URL = "https://<yourpingserver>/idp/userinfo.openid"
.. data:: PING_JWKS_URL
:noindex:
::
PING_JWKS_URL = "https://<yourpingserver>/pf/JWKS"
Notifications
=============
Lemur currently has very basic support for notifications. Notifications are send to the certificate creator, owner and
security team as specified by the `SECURITY_TEAM_EMAIL` configuration parameter.
The template for all of these notifications lives under lemur/template/event.html and can be easily modified to fit your
needs.
Certificates marked as in-active will **not** be notified of upcoming expiration. This enables a user to essentially
silence the expiration. If a certificate is active and is expiring the above will be notified at 30, 15, 5, 2 days
respectively. Lemur will not attempt to notify about certificate that have already expired.
AWS Configuration
=================
In order for Lemur to manage it's own account and other accounts we must ensure it has the correct AWS permissions.
.. note:: AWS usage is completely optional. Lemur can upload, find and manage SSL certificates in AWS. But is not required to do so.
AWS Configuration Options
-------------------------
.. data:: AWS_ACCOUNT_MAPPINGS
:noindex:
Lemur maintains it's own internal table of AWS accounts with their alias and account numbers, this variable is used during setup to bootstrap
your particular enviroment.
Defaults to ``{}``.
::
AWS_ACCOUNT_MAPPINGS = {
'awsaccountalias': 111111111111
}
Setting up IAM roles
--------------------
Lemur uses boto heavily to talk to all the AWS resources it manages. By default it uses the on-instance credentials to make the necessary calls.
In order to limit the permissions we will create a new two IAM roles for Lemur. You can name them whatever you would like but for example sake we will be calling them LemurInstanceProfile and Lemur.
Lemur uses to STS to talk to different accounts. For managing one account this isn't necessary but we will still use it so that we can easily add new accounts.
LemurInstanceProfile is the IAM role you will launch your instance with. It actually has almost no rights. In fact it should really only be able to use STS to assume role to the Lemur role.
Here is are example polices for the LemurInstanceProfile:
SES-SendEmail
.. code-block:: python
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:SendEmail"
],
"Resource": "*"
}
]
}
STS-AssumeRole
.. code-block:: python
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action":
"sts:AssumeRole",
"Resource": "*"
}
]
}
Next we will create the the Lemur IAM role. Lemur
Here is an example policy for Lemur:
IAM-ServerCertificate
.. code-block:: python
{
"Statement": [
{
"Action": [
"iam:ListServerCertificates",
"iam:UpdateServerCertificate",
"iam:GetServerCertificate",
"iam:UploadServerCertificate"
],
"Resource": [
"*"
],
"Effect": "Allow",
"Sid": "Stmt1404836868000"
}
]
}
.. code-block:: python
{
"Statement": [
{
"Action": [
"elasticloadbalancing:DescribeInstanceHealth",
"elasticloadbalancing:DescribeLoadBalancerAttributes",
"elasticloadbalancing:DescribeLoadBalancerPolicyTypes",
"elasticloadbalancing:DescribeLoadBalancerPolicies",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DeleteLoadBalancerListeners",
"elasticloadbalancing:CreateLoadBalancerListeners"
],
"Resource": [
"*"
],
"Effect": "Allow",
"Sid": "Stmt1404841912000"
}
]
}
Setting up STS access
---------------------
Once we have setup our accounts we need to ensure that we create a trust relationship so that LemurInstanceProfile can assume the Lemur role.
In the AWS console select the Lemur IAM role and select the Trust Relationships tab and click Edit Trust Relationship
Below is an example policy:
.. code-block:: python
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<awsaccountnumber>:role/LemurInstanceProfile",
]
},
"Action": "sts:AssumeRole"
}
]
}
Adding N+1 accounts
-------------------
To add another account we go to the new account and create a new Lemur IAM role with the same policy as above.
Then we would go to the account that Lemur is running is and edit the trust relationship policy.
An example policy:
.. code-block:: python
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<awsaccountnumber>:role/LemurInstanceProfile",
"arn:aws:iam::<awsaccountnumber1>:role/LemurInstanceProfile",
]
},
"Action": "sts:AssumeRole"
}
]
}
Setting up SES
--------------
Lemur has built in support for sending it's certificate notifications via Amazon's simple email service (SES). To force
Lemur to use SES ensure you are the running as the IAM role defined above and that you have followed the steps outlined
in Amazon's documentation `Setting up Amazon SES <http://docs.aws.amazon.com/ses/latest/DeveloperGuide/setting-up-ses.html>`_
The configuration::
LEMUR_MAIL = 'lemur.example.com'
Will be sender of all notifications, so ensure that it is verified with AWS.
SES if the default notification gateway and will be used unless SMTP settings are configured in the application configuration
settings.
Upgrading Lemur
===============
Lemur provides an easy way to upgrade between versions. Simply download the newest
version of Lemur from pypi and then apply any schema cahnges with the following command.
.. code-block:: bash
$ lemur db upgrade
.. note:: Internally, this uses `Alembic <https://alembic.readthedocs.org/en/latest/>`_ to manage database migrations.
.. _CommandLineInterface:
Command Line Interface
======================
Lemur installs a command line script under the name ``lemur``. This will allow you to
perform most required operations that are unachievable within the web UI.
If you're using a non-standard configuration location, you'll need to prefix every command with
--config (excluding create_config, which is a special case). For example::
lemur --config=/etc/lemur.conf.py help
For a list of commands, you can also use ``lemur help``, or ``lemur [command] --help``
for help on a specific command.
.. note:: The script is powered by a library called `Flask-Script <https://github.com/smurfix/flask-script>`_
Builtin Commands
----------------
All commands default to `~/.lemur/lemur.conf.py` if a configuration is not specified.
.. data:: create_config
Creates a default configuration file for Lemur.
Path defaults to ``~/.lemur/lemur.config.py``
::
lemur create_config .
.. note::
This command is a special case and does not depend on the configuration file
being set.
.. data:: init
Initializes the configuration file for Lemur.
::
lemur -c /etc/lemur.conf.py init
.. data:: start
Starts a Lemur service. You can also pass any flag that Gunicorn uses to specify the webserver configuration.
::
lemur start -w 6 -b 127.0.0.1:8080
.. data:: db upgrade
Performs any needed database migrations.
::
lemur db upgrade
.. data:: create_user
Creates new users within Lemur.
::
lemur create_user -u jim -e jim@example.com
.. data:: create_role
Creates new roles within Lemur.
::
lemur create_role -n example -d "a new role"
.. data:: check_revoked
Traverses every certificate that Lemur is aware of and attempts to understand it's validity.
It utilizes both OCSP and CRL. If Lemur is unable to come to a conclusion about a certificates
validity it's status is marked 'unknown'
.. data:: sync
Sync attempts to discover certificates in the environment that were not created by Lemur. There
::
lemur sync --all
Identity and Access Management
==============================
Lemur uses a Role Based Access Control (RBAC) mechanism to control which users have access to which resources. When a
user is first created in Lemur the can be assigned one or more roles. These roles are typically dynamically created
depending on a external identity provider (Google, LDAP, etc.,) or are hardcoded within Lemur and associated with special
meaning.
Within Lemur there are three main permissions: AdminPermission, CreatorPermission, OwnerPermission. Sub-permissions such
as ViewPrivateKeyPermission are compositions of these three main Permissions.
Lets take a look at how these permissions used:
Each `Authority` has a set of roles associated with it. If a user is also associated with the same roles
that the `Authority` is associated with it Lemur allows that user to user/view/update that `Authority`.
This RBAC is also used when determining which users can access which certificate private key. Lemur's current permission
structure is setup such that if the user is a `Creator` or `Owner` of a given certificate they are allow to view that
private key.
These permissions are applied to the user upon login and refreshed on every request.
.. seealso::
`Flask-Principal <https://pythonhosted.org/Flask-Principal>`_

2
docs/changelog.rst Normal file
View File

@ -0,0 +1,2 @@
Change Log
==========

262
docs/conf.py Normal file
View File

@ -0,0 +1,262 @@
# -*- coding: utf-8 -*-
#
# security_monkey documentation build configuration file, created by
# sphinx-quickstart on Sat Jun 7 18:43:48 2014.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinxcontrib.autohttp.flask',
'sphinx.ext.todo',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'lemur'
copyright = u'2015, Kevin Glisson'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'lemurdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'lemur.tex', u'Lemur Documentation',
u'Kevin Glisson', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'Lemur', u'Lemur Documentation',
[u'Kevin Glisson'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'Lemur', u'Lemur Documentation',
u'Kevin Glisson', 'Lemur', 'SSL Certificate Management',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

197
docs/developer/index.rst Normal file
View File

@ -0,0 +1,197 @@
Contributing
============
Want to contribute back to Lemur? This page describes the general development flow,
our philosophy, the test suite, and issue tracking.
Documentation
-------------
If you're looking to help document Lemur, you can get set up with Sphinx, our documentation tool,
but first you will want to make sure you have a few things on your local system:
* python-dev (if you're on OS X, you already have this)
* pip
* virtualenvwrapper
Once you've got all that, the rest is simple:
::
# If you have a fork, you'll want to clone it instead
git clone git://github.com/netflix/lemur.git
# Create a python virtualenv
mkvirtualenv lemur
# Make the magic happen
make dev-docs
Running ``make dev-docs`` will install the basic requirements to get Sphinx running.
Building Documentation
~~~~~~~~~~~~~~~~~~~~~~
Inside the ``docs`` directory, you can run ``make`` to build the documentation.
See ``make help`` for available options and the `Sphinx Documentation <http://sphinx-doc.org/contents.html>`_ for more information.
Developing Against HEAD
-----------------------
We try to make it easy to get up and running in a development environment using a git checkout
of Lemur. You'll want to make sure you have a few things on your local system first:
* python-dev (if you're on OS X, you already have this)
* pip
* virtualenv (ideally virtualenvwrapper)
* node.js (for npm and building css/javascript)
* (Optional) Potgresql
Once you've got all that, the rest is simple:
::
# If you have a fork, you'll want to clone it instead
git clone git://github.com/lemur/lemur.git
# Create a python virtualenv
mkvirtualenv lemur
# Make the magic happen
make
Running ``make`` will do several things, including:
* Setting up any submodules (including Bootstrap)
* Installing Python requirements
* Installing NPM requirements
.. note::
You will want to store your virtualenv out of the ``lemur`` directory you cloned above,
otherwise ``make`` will fail.
Create a default Lemur configuration just as if this were a production instance:
::
lemur init
You'll likely want to make some changes to the default configuration (we recommend developing against Postgres, for example). Once done, migrate your database using the following command:
::
lemur upgrade
.. note:: The ``upgrade`` shortcut is simply a shorcut to Alembic's upgrade command.
Coding Standards
----------------
Lemur follows the guidelines laid out in `pep8 <http://www.python.org/dev/peps/pep-0008/>`_ with a little bit
of flexibility on things like line length. We always give way for the `Zen of Python <http://www.python.org/dev/peps/pep-0020/>`_. We also use strict mode for JavaScript, enforced by jshint.
You can run all linters with ``make lint``, or respectively ``lint-python`` or ``lint-js``.
Spacing
~~~~~~~
Python:
4 Spaces
JavaScript:
2 Spaces
CSS:
2 Spaces
HTML:
2 Spaces
Running the Test Suite
----------------------
The test suite consists of multiple parts, testing both the Python and JavaScript components in Lemur. If you've setup your environment correctly, you can run the entire suite with the following command:
::
make test
If you only need to run the Python tests, you can do so with ``make test-python``, as well as ``test-js`` for the JavaScript tests.
You'll notice that the test suite is structured based on where the code lives, and strongly encourages using the mock library to drive more accurate individual tests.
.. note:: We use py.test for the Python test suite, and a combination of phantomjs and jasmine for the JavaScript tests.
Static Media
------------
Lemur uses a library that compiles it's static media assets (LESS and JS files) automatically. If you're developing using
runserver you'll see changes happen not only in the original files, but also the minified or processed versions of the file.
If you've made changes and need to compile them by hand for any reason, you can do so by running:
::
lemur compilestatic
The minified and processed files should be committed alongside the unprocessed changes.
Developing with Flask
----------------------
Because Lemur is just Flask, you can use all of the standard Flask functionality. The only difference is you'll be accessing commands that would normally go through manage.py using the ``lemur`` CLI helper instead.
For example, you probably don't want to use ``lemur start`` for development, as it doesn't support anything like
automatic reloading on code changes. For that you'd want to use the standard builtin ``runserver`` command:
::
lemur runserver
DDL (Schema Changes)
--------------------
Schema changes should always introduce the new schema in a commit, and then introduce code relying on that schema in a followup commit. This also means that new columns must be NULLable.
Removing columns and tables requires a slightly more painful flow, and should resemble the follow multi-commit flow:
- Remove all references to the column or table (but dont remove the Model itself)
- Remove the model code
- Remove the table or column
Contributing Back Code
----------------------
All patches should be sent as a pull request on GitHub, include tests, and documentation where needed. If you're fixing a bug or making a large change the patch **must** include test coverage.
Uncertain about how to write tests? Take a look at some existing tests that are similar to the code you're changing, and go from there.
You can see a list of open pull requests (pending changes) by visiting https://github.com/netflix/lemur/pulls
Plugins
=======
.. toctree::
:maxdepth: 1
plugins/index
Internals
=========
.. toctree::
:maxdepth: 1
internals/lemur

View File

@ -0,0 +1,20 @@
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:

View File

@ -0,0 +1,11 @@
analyze Package
===============
:mod:`service` Module
---------------------
.. automodule:: lemur.analyze.service
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,20 @@
auth Package
============
:mod:`permissions` Module
-------------------------
.. automodule:: lemur.auth.permissions
:members:
:undoc-members:
:show-inheritance:
:mod:`service` Module
---------------------
.. automodule:: lemur.auth.service
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,20 @@
authorities Package
===================
:mod:`models` Module
--------------------
.. automodule:: lemur.authorities.models
:members:
:undoc-members:
:show-inheritance:
:mod:`service` Module
---------------------
.. automodule:: lemur.authorities.service
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,43 @@
certificates Package
====================
:mod:`exceptions` Module
------------------------
.. automodule:: lemur.certificates.exceptions
:members:
:undoc-members:
:show-inheritance:
:mod:`models` Module
--------------------
.. automodule:: lemur.certificates.models
:members:
:undoc-members:
:show-inheritance:
:mod:`service` Module
---------------------
.. automodule:: lemur.certificates.service
:members:
:undoc-members:
:show-inheritance:
:mod:`sync` Module
------------------
.. automodule:: lemur.certificates.sync
:members:
:undoc-members:
:show-inheritance:
:mod:`verify` Module
--------------------
.. automodule:: lemur.certificates.verify
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,34 @@
common Package
==============
:mod:`crypto` Module
--------------------
.. automodule:: lemur.common.crypto
:members:
:undoc-members:
:show-inheritance:
:mod:`health` Module
--------------------
.. automodule:: lemur.common.health
:members:
:undoc-members:
:show-inheritance:
:mod:`utils` Module
-------------------
.. automodule:: lemur.common.utils
:members:
:undoc-members:
:show-inheritance:
Subpackages
-----------
.. toctree::
lemur.common.services

View File

@ -0,0 +1,35 @@
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:

View File

@ -0,0 +1,19 @@
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:

View File

@ -0,0 +1,11 @@
plugins Package
===============
Subpackages
-----------
.. toctree::
lemur.common.services.issuers.plugins.cloudca
lemur.common.services.issuers.plugins.verisign

View File

@ -0,0 +1,19 @@
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:

View File

@ -0,0 +1,26 @@
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

View File

@ -0,0 +1,11 @@
services Package
================
Subpackages
-----------
.. toctree::
lemur.common.services.aws
lemur.common.services.issuers

View File

@ -0,0 +1,19 @@
domains Package
===============
:mod:`models` Module
--------------------
.. automodule:: lemur.domains.models
:members:
:undoc-members:
:show-inheritance:
:mod:`service` Module
---------------------
.. automodule:: lemur.domains.service
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,35 @@
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:

View File

@ -0,0 +1,27 @@
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:

View File

@ -0,0 +1,20 @@
roles Package
=============
:mod:`models` Module
--------------------
.. automodule:: lemur.roles.models
:members:
:undoc-members:
:show-inheritance:
:mod:`service` Module
---------------------
.. automodule:: lemur.roles.service
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,87 @@
:mod:`constants` Module
-----------------------
.. automodule:: lemur.constants
:members:
:undoc-members:
:show-inheritance:
:mod:`database` Module
----------------------
.. automodule:: lemur.database
:members:
:undoc-members:
:show-inheritance:
:mod:`decorators` Module
------------------------
.. automodule:: lemur.decorators
:members:
:undoc-members:
:show-inheritance:
:mod:`exceptions` Module
------------------------
.. automodule:: lemur.exceptions
:members:
:undoc-members:
:show-inheritance:
:mod:`extensions` Module
------------------------
.. automodule:: lemur.extensions
:members:
:undoc-members:
:show-inheritance:
:mod:`factory` Module
---------------------
.. automodule:: lemur.factory
:members:
:undoc-members:
:show-inheritance:
:mod:`manage` Module
--------------------
.. automodule:: lemur.manage
:members:
:undoc-members:
:show-inheritance:
:mod:`models` Module
--------------------
.. automodule:: lemur.models
:members:
:undoc-members:
:show-inheritance:
:mod:`notifications` Module
---------------------------
.. automodule:: lemur.notifications
:members:
:undoc-members:
:show-inheritance:
Subpackages
-----------
.. toctree::
lemur.accounts
lemur.auth
lemur.authorities
lemur.certificates
lemur.common
lemur.domains
lemur.roles
lemur.status
lemur.users

View File

@ -0,0 +1,11 @@
status Package
==============
:mod:`views` Module
-------------------
.. automodule:: lemur.status.views
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,19 @@
users Package
=============
:mod:`models` Module
--------------------
.. automodule:: lemur.users.models
:members:
:undoc-members:
:show-inheritance:
:mod:`service` Module
---------------------
.. automodule:: lemur.users.service
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,151 @@
Writing a Plugin
================
**The plugin interface is a work in progress.**
Several interfaces exist for extending Lemur:
* Issuers (lemur.issuers)
Structure
---------
A plugins layout generally looks like the following::
setup.py
lemur_pluginname/
lemur_pluginname/__init__.py
lemur_pluginname/plugin.py
The ``__init__.py`` file should contain no plugin logic, and at most, a VERSION = 'x.x.x' line. For example,
if you want to pull the version using pkg_resources (which is what we recommend), your file might contain::
try:
VERSION = __import__('pkg_resources') \
.get_distribution(__name__).version
except Exception, e:
VERSION = 'unknown'
Inside of ``plugin.py``, you'll declare your Plugin class::
import lemur_pluginname
from lemur.common.services.issuers.plugins import Issuer
class PluginName(Plugin):
title = 'Plugin Name'
slug = 'pluginname'
description = 'My awesome plugin!'
version = lemur_pluginname.VERSION
author = 'Your Name'
author_url = 'https://github.com/yourname/lemur_pluginname'
def widget(self, request, group, **kwargs):
return "<p>Absolutely useless widget</p>"
And you'll register it via ``entry_points`` in your ``setup.py``::
setup(
# ...
entry_points={
'lemur.plugins': [
'pluginname = lemur_pluginname.issuers:PluginName'
],
},
)
That's it! Users will be able to install your plugin via ``pip install <package name>`` and configure it
via the web interface based on the hooks you enabled.
Permissions
===========
As described in the plugin interface, Lemur provides a suite of permissions.
In most cases, a admin (that is, if User.is_admin is ``True``), will be granted implicit permissions
on everything.
This page attempts to describe those permissions, and the contextual objects along with them.
.. data:: add_project
Controls whether a user can create a new project.
::
>>> has_perm('add_project', user)
Testing
=======
Lemur provides a basic py.test-based testing framework for extensions.
In a simple project, you'll need to do a few things to get it working:
setup.py
--------
Augment your setup.py to ensure at least the following:
.. code-block:: python
setup(
# ...
install_requires=[
'lemur',
]
)
conftest.py
-----------
The ``conftest.py`` file is our main entry-point for py.test. We need to configure it to load the Lemur pytest configuration:
.. code-block:: python
from __future__ import absolute_import
pytest_plugins = [
'lemur.utils.pytest'
]
Test Cases
----------
You can now inherit from Lemur's core test classes. These are Django-based and ensure the database and other basic utilities are in a clean state:
.. code-block:: python
# test_myextension.py
from __future__ import absolute_import
from lemur.testutils import TestCase
class MyExtensionTest(TestCase):
def test_simple(self):
assert 1 != 2
Running Tests
-------------
Running tests follows the py.test standard. As long as your test files and methods are named appropriately (``test_filename.py`` and ``test_function()``) you can simply call out to py.test:
::
$ py.test -v
============================== test session starts ==============================
platform darwin -- Python 2.7.9 -- py-1.4.26 -- pytest-2.6.4/python2.7
plugins: django
collected 1 items
tests/test_myextension.py::MyExtensionTest::test_simple PASSED
=========================== 1 passed in 0.35 seconds ============================

60
docs/developer/rest.rst Normal file
View File

@ -0,0 +1,60 @@
Lemur's front end is entirely API driven. Any action that you can accomplish via the UI can also be accomplished by the
UI. The following is documents and provides examples on how to make requests to the Lemur API.
Authentication
--------------
.. automodule:: lemur.auth.views
:members:
:undoc-members:
:show-inheritance:
Accounts
--------
.. automodule:: lemur.accounts.views
:members:
:undoc-members:
:show-inheritance:
Users
-----
.. automodule:: lemur.users.views
:members:
:undoc-members:
:show-inheritance:
Roles
-----
.. automodule:: lemur.roles.views
:members:
:undoc-members:
:show-inheritance:
Certificates
------------
.. automodule:: lemur.certificates.views
:members:
:undoc-members:
:show-inheritance:
Authorities
-----------
.. automodule:: lemur.authorities.views
:members:
:undoc-members:
:show-inheritance:
Domains
-------
.. automodule:: lemur.domains.views
:members:
:undoc-members:
:show-inheritance:

30
docs/faq.rst Normal file
View File

@ -0,0 +1,30 @@
Frequently Asked Questions
==========================
Common Problems
---------------
In my startup logs I see *'Aborting... Lemur cannot locate db encryption key, is ENCRYPTION_KEY set?'*
You likely have not correctly configured **ENCRYPTION_KEY**. See
:doc:`administration/configuration` for more information.
How do I
--------
... script the Lemur installation to bootstrap things like roles and users?
Lemur is a simple Flask (Python) application that runs using a utility
runner. A script that creates a project and default user might look something
like this:
.. code-block:: python
# Bootstrap the Flask environment
from flask import current_app
from lemur.users.service import create as create_user
from lemur.roles.service import create as create_role
from lemur.accounts.service import create as create_account
role = create_role('aRole', 'this is a new role')
create_user('admin', 'password', 'lemur@nobody', True, [role]

10
docs/guide/index.rst Normal file
View File

@ -0,0 +1,10 @@
Creating Certificates
=====================
Creating Users
==============
Creating Roles
==============

67
docs/index.rst Normal file
View File

@ -0,0 +1,67 @@
Lemur
=====
Lemur is a SSL management service. It attempts to help track and create certificates. By removing common issues with
CSR creation it gives normal developers 'sane' SSL defaults and helps security teams push SSL usage throughout an organization.
Installation
------------
.. toctree::
:maxdepth: 2
quickstart/index
production/index
User Guide
----------
.. toctree::
:maxdepth: 2
guide/index
Administration
--------------
.. toctree::
:maxdepth: 2
administration/index
plugins/index
Developers
----------
.. toctree::
:maxdepth: 2
developer/index
REST API
--------
.. toctree::
:maxdepth: 2
developer/rest
FAQ
----
.. toctree::
:maxdepth: 1
faq
Reference
---------
.. toctree::
:maxdepth: 1
changelog
license/index

20
docs/license/index.rst Normal file
View File

@ -0,0 +1,20 @@
License
=======
Lemur is licensed under a three clause APACHE License.
The full license text can be found below (:ref:`lemur-license`).
Authors
-------
Lemur was originally written and is maintained by Kevin Glisson.
A list of additional contributors can be seen on `GitHub <https://github.com/netflix/lemur/contributors>`_.
.. _lemur-license:
Lemur License
-------------
.. include:: ../../LICENSE

20
docs/plugins/index.rst Normal file
View File

@ -0,0 +1,20 @@
Plugins
=======
There are several interfaces currently available to extend Lemur. These are a work in
progress and the API is not frozen.
Bundled Plugins
---------------
Lemur includes several plugins by default. Including extensive support for AWS, VeriSign/Symantec and CloudCA services.
3rd Party Extensions
--------------------
The following extensions are available and maintained by members of the Lemur community:
Have an extension that should be listed here? Submit a `pull request <https://github.com/netflix/lemur>`_ and we'll
get it added.
Want to create your own extension? See :doc:`../developer/plugins/index` to get started.

277
docs/production/index.rst Normal file
View File

@ -0,0 +1,277 @@
Production
**********
There are several steps needed to make Lemur production ready. Here we focus on making Lemur more reliable and secure.
Basics
======
Because of the sensitivity of the information stored and maintain by Lemur it is important that you follow standard host hardening practices:
- Run Lemur with a limited user
- Disabled any unneeded service
- Enable remote logging
.. _CredentialManagement:
Credential Management
---------------------
Lemur often contains credentials such as mutual SSL keys that are used to communicate with third party resources and for encrypting stored secrets. Lemur comes with the ability
to automatically encrypt these keys such that your keys not be in clear text.
The keys are located within lemur/keys and broken down by environment
To utilize this ability use the following commands:
``lemur lock``
and
``lemur unlock``
If you choose to use this feature ensure that the KEY are decrypted before Lemur starts as it will have trouble communicating with the database otherwise.
SSL
====
Nginx
-----
Nginx is a very popular choice to serve a Python project:
- It's fast.
- It's lightweight.
- Configuration files are simple.
Nginx doesn't run any Python process, it only serves requests from outside to
the Python server.
Therefor there are two steps:
- Run the Python process.
- Run Nginx.
You will benefit from having:
- the possibility to have several projects listening to the port 80;
- your web site processes won't run with admin rights, even if --user doesn't
work on your OS;
- the ability to manage a Python process without touching Nginx or the other
processes. It's very handy for updates.
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.
You can make some adjustments to get a better user experience::
server_tokens off;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443;
access_log /var/log/nginx/log/lemur.access.log;
error_log /var/log/nginx/log/lemur.error.log;
location /api {
proxy_pass http://127.0.0.1:5000;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
root /apps/lemur/lemur/static/dist;
index index.html;
}
}
This makes Nginx serve the favicon and static files which is is much better at than python.
It is highly recommended that you deploy SSL when deploying Lemur. This may be obvious given Lemur's purpose but the
sensitive nature of Lemur and what it controls makes this essential. This is a sample config for Lemur that also terminates SSL::
server_tokens off;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443;
access_log /var/log/nginx/log/lemur.access.log;
error_log /var/log/nginx/log/lemur.error.log;
# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
ssl_certificate /path/to/signed_cert_plus_intermediates;
ssl_certificate_key /path/to/private_key;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /path/to/dhparam.pem;
# modern configuration. tweak to your needs.
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
ssl_prefer_server_ciphers on;
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
add_header Strict-Transport-Security max-age=15768000;
# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;
## verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
resolver <IP DNS resolver>;
location /api {
proxy_pass http://127.0.0.1:5000;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
root /apps/lemur/lemur/static/dist;
index index.html;
}
}
Apache
------
An example apache config::
<VirtualHost *:443>
...
SSLEngine on
SSLCertificateFile /path/to/signed_certificate
SSLCertificateChainFile /path/to/intermediate_certificate
SSLCertificateKeyFile /path/to/private/key
SSLCACertificateFile /path/to/all_ca_certs
# intermediate configuration, tweak to your needs
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
SSLHonorCipherOrder on
# HSTS (mod_headers is required) (15768000 seconds = 6 months)
Header always set Strict-Transport-Security "max-age=15768000"
...
</VirtualHost>
Also included in the configurations above are several best practices when it comes to deploying SSL. Things like enabling
HSTS, disabling vulnerable ciphers are all good ideas when it comes to deploying Lemur into a production environment.
.. seealso::
`Mozilla SSL Configuration Generator <https://mozilla.github.io/server-side-tls/ssl-config-generator/>`_
.. _UsingSupervisor:
Supervisor
==========
Supervisor is a very nice way to manage you Python processes. We won't cover
the setup (which is just apt-get install supervisor or pip install supervisor
most of the time), but here is a quick overview on how to use it.
Create a configuration file named supervisor.ini::
[unix_http_server]
file=/tmp/supervisor.sock;
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock;
[rpcinterface:supervisor]
supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface
[supervisord]
logfile=/tmp/lemur.log
logfile_maxbytes=50MB
logfile_backups=2
loglevel=trace
pidfile=/tmp/supervisord.pid
nodaemon=false
minfds=1024
minprocs=200
user=lemur
[program:lemur]
command=python /path/to/lemur/manage.py manage.py start
directory=/path/to/lemur/
environment=PYTHONPATH='/path/to/lemur/'
user=lemur
autostart=true
autorestart=true
The 4 first entries are just boiler plate to get you started, you can copy
them verbatim.
The last one define one (you can have many) process supervisor should manage.
It means it will run the command::
python manage.py start
In the directory, with the environment and the user you defined.
This command will be ran as a daemon, in the background.
`autostart` and `autorestart` just make it fire and forget: the site will always be
running, even it crashes temporarily or if you restart the machine.
The first time you run supervisor, pass it the configuration file::
supervisord -c /path/to/supervisor.ini
Then you can manage the process by running::
supervisorctl -c /path/to/supervisor.ini
It will start a shell from were you can start/stop/restart the service
You can read all errors that might occurs from /tmp/lemur.log.

237
docs/quickstart/index.rst Normal file
View File

@ -0,0 +1,237 @@
Quickstart
**********
This guide will step you through setting up a Python-based virtualenv, installing the required packages, and configuring the basic web service.
Dependencies
------------
Some basic prerequisites which you'll need in order to run Lemur:
* A UNIX-based operating system. We test on Ubuntu, develop on OS X
* Python 2.7
* PostgreSQL
* Ngnix
.. note:: Lemur was built with in AWS in mind. This means that things such as databases (RDS), mail (SES), and SSL (ELB),
are largely handled for us. Lemur does **not** require AWS to function. Our guides and documentation try to be
be as generic as possible and are not intended to document every step of launching Lemur into a given environment.
Setting up an Environment
-------------------------
The first thing you'll need is the Python ``virtualenv`` package. You probably already
have this, but if not, you can install it with::
pip install -U virtualenv
Once that's done, choose a location for the environment, and create it with the ``virtualenv``
command. For our guide, we're going to choose ``/www/lemur/``::
virtualenv /www/lemur/
Finally, activate your virtualenv::
source /www/lemur/bin/activate
.. note:: Activating the environment adjusts your PATH, so that things like pip now
install into the virtualenv by default.
Installing Lemur
----------------
Once you've got the environment setup, you can install Lemur and all its dependencies with
the same command you used to grab virtualenv::
pip install -U lemur
Once everything is installed, you should be able to execute the Lemur CLI, via ``lemur``, and get something
like the following:
.. code-block:: bash
$ lemur
usage: lemur [--config=/path/to/settings.py] [command] [options]
Installing from Source
~~~~~~~~~~~~~~~~~~~~~~
If you're installing the Lemur source (e.g. from git), you'll also need to install **npm**.
Once your system is prepared, symlink your source into the virtualenv:
.. code-block:: bash
$ python setup.py develop
.. Note:: This command will install npm dependencies as well as compile static assets.
Creating a configuration
------------------------
Before we run Lemur we must create a valid configuration file for it.
The Lemur cli comes with a simple command to get you up and running quickly.
Simply run:
.. code-block:: bash
$ lemur create_config
.. Note:: This command will create a default configuration under `~/.lemur/lemur.conf.py` you
can specify this location by passing the `config_path` parameter to the `create_config` command.
You can specify `-c` or `--config` to any Lemur command to specify the current environment
you are working in. Lemur will also look under the environmental variable `LEMUR_CONF` should
that be easier to setup in your environment.
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..
Initializing Lemur
------------------
Lemur provides a helpful command that will initialize your database for you. It creates a default user (lemur) that is
used by Lemur to help associate certificates that do not currently have an owner. This is most commonly the case when
Lemur has discovered certificates from a third party resource. This is also a default user that can be used to
administer Lemur.
.. code-block:: bash
$ lemur init
.. note:: It is recommended that once the 'lemur' user is created that you create individual users for every day access.
There is currently no way for a user to self enroll for Lemur access, they must have an administrator create an account
for them or be enrolled automatically through SSO. This can be done through the CLI or UI.
See :ref:`Creating Users <CreatingUsers>` and :ref:`Command Line Interface <CommandLineInterface>` 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 <http://www.postgresql.org/docs/9.0/static/tutorial-createdb.html>`_
for details.
Starting the Web Service
------------------------
Lemur provides a built-in webserver (powered by gunicorn and eventlet) to get you off the ground quickly.
To start the webserver, you simply use ``lemur start``. If you opted to use an alternative configuration path
you can pass that via the --config option.
::
# Lemur's server runs on port 5000 by default. Make sure your client reflects
# the correct host and port!
lemur --config=/etc/lemur.conf.py start
You should now be able to test the web service by visiting `http://localhost:5000/`.
Setup a Reverse Proxy
---------------------
By default, Lemur runs on port 5000. Even if you change this, under normal conditions you won't be able to bind to
port 80. To get around this (and to avoid running Lemur as a privileged user, which you shouldn't), we recommend
you setup a simple web proxy.
Proxying with Nginx
~~~~~~~~~~~~~~~~~~~
You'll use the builtin HttpProxyModule within Nginx to handle proxying::
location / {
proxy_pass http://localhost:5000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
See :doc:`../production/index` for more details on using Nginx.
Proxying with Apache
~~~~~~~~~~~~~~~~~~~~
Apache requires the use of mod_proxy for forwarding requests::
ProxyPass / http://localhost:5000/
ProxyPassReverse / http://localhost:5000/
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https" env=HTTPS
You will need to enable ``headers``, ``proxy``, and ``proxy_http`` apache modules to use these settings.
See :doc:`../production/index` for more details on using Apache.
Running Lemur as a Service
---------------------------
We recommend using whatever software you are most familiar with for managing Lemur processes. One option is
`Supervisor <http://supervisord.org/>`_.
Configure ``supervisord``
~~~~~~~~~~~~~~~~~~~~~~~~~
Configuring Supervisor couldn't be more simple. Just point it to the ``lemur`` executable in your virtualenv's bin/
folder and you're good to go.
::
[program:lemur-web]
directory=/www/lemur/
command=/www/lemur/bin/lemur start
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile syslog
stderr_logfile syslog
See :ref:`Using Supervisor <UsingSupervisor>` for more details on using Supervisor.
Syncing
-------
Lemur uses periodic sync tasks to make sure it is up-to-date with it's environment. As always things can change outside
of Lemur, but we do our best to reconcile those changes.
.. code-block:: bash
$ crontab -e
* 3 * * * lemur sync
* 3 * * * lemur check_revoked
Additional Utilities
--------------------
If you're familiar with Python you'll quickly find yourself at home, and even more so if you've used Flask. The
``lemur`` command is just a simple wrapper around Flask's ``manage.py``, which means you get all of the
power and flexibility that goes with it.
Some of those which you'll likely find useful are:
lock
~~~~
Encrypts sensitive key material - This is most useful for storing encrypted secrets in source code.
unlock
~~~~~~
Decrypts sensitive key material - Used to decrypt the secrets stored in source during deployment.
What's Next?
------------
The above gets you going, but for production there are several different security considerations to take into account,
remember Lemur is handling sensitive data and security is imperative.
See :doc:`../production/index` for more details on how to configure Lemur for production.