Configuration

Warning

There are many secrets that Lemur uses that must be protected. All of these options are set via the Lemur configuration 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 Credential Management for more information.

Note

All configuration values are python strings unless otherwise noted.

Basic Configuration

LOG_LEVEL
LOG_LEVEL = "DEBUG"
LOG_FILE
LOG_FILE = "/logs/lemur/lemur-test.log"
DEBUG

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.

CORS

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
SQLALCHEMY_DATABASE_URI
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'
LEMUR_ALLOW_WEEKEND_EXPIRATION
Specifies whether to allow certificates created by Lemur to expire on weekends. Default is True.
LEMUR_WHITELISTED_DOMAINS

List of regular expressions for domain restrictions; if the list is not empty, normal users can only issue certificates for domain names matching at least one pattern on this list. Administrators are exempt from this restriction.

Cerificate common name is matched against these rules if it does not contain a space. SubjectAltName DNS names are always matched against these rules.

Take care to write patterns in such way to not allow the * wildcard character inadvertently. To match a . character, it must be escaped (as .).

LEMUR_OWNER_EMAIL_IN_SUBJECT
By default, Lemur will add the certificate owner’s email address to certificate subject (for CAs that allow it). Set this to False to disable this.
LEMUR_TOKEN_SECRET
The TOKEN_SECRET is the secret used to create JWT tokens that are given out to users. This should be securely generated and kept private.
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))
LEMUR_ENCRYPTION_KEYS

The LEMUR_ENCRYPTION_KEYS is used to encrypt data at rest within Lemur’s database. Without a key Lemur will refuse to start. Multiple keys can be provided to facilitate key rotation. The first key in the list is used for encryption and all keys are tried for decryption until one works. Each key must be 32 URL safe base-64 encoded bytes.

Running lemur create_config will securely generate a key for your configuration file. If you would like to generate your own, we recommend the following method:

>>> import os
>>> import base64
>>> base64.urlsafe_b64encode(os.urandom(32))
LEMUR_ENCRYPTION_KEYS = ['1YeftooSbxCiX2zo8m1lXtpvQjy27smZcUUaGmffhMY=', 'LAfQt6yrkLqOK5lwpvQcT4jf2zdeTQJV1uYeh9coT5s=']
DEBUG_DUMP
Dump all imported or generated CSR and certificate details to stdout using OpenSSL. (default: False)

Certificate Default Options

Lemur allows you to fine tune your certificates to your organization. The following defaults are presented in the UI and are used when Lemur creates the CSR for your certificates.

LEMUR_DEFAULT_COUNTRY
LEMUR_DEFAULT_COUNTRY = "US"
LEMUR_DEFAULT_STATE
LEMUR_DEFAULT_STATE = "California"
LEMUR_DEFAULT_LOCATION
LEMUR_DEFAULT_LOCATION = "Los Gatos"
LEMUR_DEFAULT_ORGANIZATION
LEMUR_DEFAULT_ORGANIZATION = "Netflix"
LEMUR_DEFAULT_ORGANIZATIONAL_UNIT
LEMUR_DEFAULT_ORGANIZATIONAL_UNIT = "Operations"
LEMUR_DEFAULT_ISSUER_PLUGIN
LEMUR_DEFAULT_ISSUER_PLUGIN = "verisign-issuer"
LEMUR_DEFAULT_AUTHORITY
LEMUR_DEFAULT_AUTHORITY = "verisign"

Notification Options

Lemur currently has very basic support for notifications. Currently only expiration notifications are supported. Actual notification is handled by the notification plugins that you have configured. Lemur ships with the ‘Email’ notification that allows expiration emails to be sent to subscribers.

Templates for expiration emails are located under lemur/plugins/lemur_email/templates and can be modified for your needs. Notifications are sent to the certificate creator, owner and security team as specified by the LEMUR_SECURITY_TEAM_EMAIL configuration parameter.

Certificates marked as inactive 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 according to the LEMUR_DEFAULT_EXPIRATION_NOTIFICATION_INTERVALS or 30, 15, 2 days before expiration if no intervals are set.

Lemur supports sending certification expiration notifications through SES and SMTP.

LEMUR_EMAIL_SENDER

Specifies which service will be delivering notification emails. Valid values are SMTP or SES

Note

If using SMTP as your provider you will need to define additional configuration options as specified by Flask-Mail. See: Flask-Mail

If you are using SES the email specified by the LEMUR_MAIL configuration will need to be verified by AWS before you can send any mail. See: Verifying Email Address in Amazon SES

LEMUR_EMAIL

Lemur sender’s email

LEMUR_EMAIL = 'lemur.example.com'
LEMUR_SECURITY_TEAM_EMAIL

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']
LEMUR_DEFAULT_EXPIRATION_NOTIFICATION_INTERVALS

Lemur notification intervals

LEMUR_DEFAULT_EXPIRATION_NOTIFICATION_INTERVALS = [30, 15, 2]

Authentication Options

Lemur currently supports Basic Authentication, LDAP Authentication, Ping OAuth2, and Google out of the box. Additional flows can be added relatively easily.

LDAP Options

Lemur supports the use of an LDAP server in conjunction with Basic Authentication. Lemur local users can still be defined and take precedence over LDAP users. If a local user does not exist, LDAP will be queried for authentication. Only simple ldap binding with or without TLS is supported.

LDAP support requires the pyldap python library, which also depends on the following openldap packages.

$ sudo apt-get update
$ sudo apt-get install libldap2-dev libsasl2-dev libldap2-dev libssl-dev

To configure the use of an LDAP server, a number of settings need to be configured in lemur.conf.py.

Here is an example LDAP configuration stanza you can add to your config. Adjust to suit your environment of course.

LDAP_AUTH = True
LDAP_BIND_URI='ldaps://secure.evilcorp.net'
LDAP_BASE_DN='DC=users,DC=evilcorp,DC=net'
LDAP_EMAIL_DOMAIN='evilcorp.net'
LDAP_USE_TLS = True
LDAP_CACERT_FILE = '/opt/lemur/trusted.pem'
LDAP_REQUIRED_GROUP = 'certificate-management-access'
LDAP_GROUPS_TO_ROLES = {'certificate-management-admin': 'admin', 'certificate-management-read-only': 'read-only'}

The lemur ldap module uses the user principal name (upn) of the authenticating user to bind. This is done once for each user at login time. The UPN is effectively the email address in AD/LDAP of the user. If the user doesn’t provide the email address, it constructs one based on the username supplied (which should normally match the samAccountName) and the value provided by the config LDAP_EMAIL_DOMAIN. The config LDAP_BASE_DN tells lemur where to search within the AD/LDAP tree for the given UPN (user). If the bind with those credentials is successful - there is a valid user in AD with correct password.

Each of the LDAP options are described below.

LDAP_AUTH

This enables the use of LDAP

LDAP_AUTH = True
LDAP_BIND_URI

Specifies the LDAP server connection string

LDAP_BIND_URI = 'ldaps://hostname'
LDAP_BASE_DN

Specifies the LDAP distinguished name location to search for users

LDAP_BASE_DN = 'DC=Users,DC=Evilcorp,DC=com'
LDAP_EMAIL_DOMAIN

The email domain used by users in your directory. This is used to build the userPrincipalName to search with.

LDAP_EMAIL_DOMAIN = 'evilcorp.com'

The following LDAP options are not required, however TLS is always recommended.

LDAP_USE_TLS

Enables the use of TLS when connecting to the LDAP server. Ensure the LDAP_BIND_URI is using ldaps scheme.

LDAP_USE_TLS = True
LDAP_CACERT_FILE

Specify a Certificate Authority file containing PEM encoded trusted issuer certificates. This can be used if your LDAP server is using certificates issued by a private CA.

LDAP_CACERT_FILE = '/path/to/cacert/file'
LDAP_REQUIRED_GROUP

Lemur has pretty open permissions. You can define an LDAP group to specify who can access Lemur. Only members of this group will be able to login.

LDAP_REQUIRED_GROUP = 'Lemur LDAP Group Name'
LDAP_GROUPS_TO_ROLES

You can also define a dictionary of ldap groups mapped to lemur roles. This allows you to use ldap groups to manage access to owner/creator roles in Lemur

LDAP_GROUPS_TO_ROLES = {'lemur_admins': 'admin', 'Lemur Team DL Group': 'team@example.com'}

Authentication Providers

If you are not using an authentication provider you do not need to configure any of these options.

For more information about how to use social logins, see: Satellizer

ACTIVE_PROVIDERS
ACTIVE_PROVIDERS = ["ping", "google", "oauth2"]
PING_SECRET
PING_SECRET = 'somethingsecret'
PING_ACCESS_TOKEN_URL
PING_ACCESS_TOKEN_URL = "https://<yourpingserver>/as/token.oauth2"
PING_USER_API_URL
PING_USER_API_URL = "https://<yourpingserver>/idp/userinfo.openid"
PING_JWKS_URL
PING_JWKS_URL = "https://<yourpingserver>/pf/JWKS"
PING_NAME
PING_NAME = "Example Oauth2 Provider"
PING_CLIENT_ID
PING_CLIENT_ID = "client-id"
PING_REDIRECT_URI
PING_REDIRECT_URI = "https://<yourlemurserver>/api/1/auth/ping"
PING_AUTH_ENDPOINT
PING_AUTH_ENDPOINT = "https://<yourpingserver>/oauth2/authorize"
OAUTH2_SECRET
OAUTH2_SECRET = 'somethingsecret'
OAUTH2_ACCESS_TOKEN_URL
OAUTH2_ACCESS_TOKEN_URL = "https://<youroauthserver> /oauth2/v1/authorize"
OAUTH2_USER_API_URL
OAUTH2_USER_API_URL = "https://<youroauthserver>/oauth2/v1/userinfo"
OAUTH2_JWKS_URL
OAUTH2_JWKS_URL = "https://<youroauthserver>/oauth2/v1/keys"
OAUTH2_NAME
OAUTH2_NAME = "Example Oauth2 Provider"
OAUTH2_CLIENT_ID
OAUTH2_CLIENT_ID = "client-id"
OAUTH2_REDIRECT_URI
OAUTH2_REDIRECT_URI = "https://<yourlemurserver>/api/1/auth/oauth2"
OAUTH2_AUTH_ENDPOINT
OAUTH2_AUTH_ENDPOINT = "https://<youroauthserver>/oauth2/v1/authorize"
OAUTH2_VERIFY_CERT
OAUTH2_VERIFY_CERT = True
GOOGLE_CLIENT_ID
GOOGLE_CLIENT_ID = "client-id"
GOOGLE_SECRET
GOOGLE_SECRET = "somethingsecret"

Plugin Specific Options

Authorities will each have their own configuration options. There is currently just one plugin bundled with Lemur, Verisign/Symantec. Additional plugins may define additional options. Refer to the plugin’s own documentation for those plugins.

VERISIGN_URL
This is the url for the Verisign API
VERISIGN_PEM_PATH
This is the path to the mutual TLS certificate used for communicating with Verisign
VERISIGN_FIRST_NAME
This is the first name to be used when requesting the certificate
VERISIGN_LAST_NAME
This is the last name to be used when requesting the certificate
VERISIGN_EMAIL
This is the email to be used when requesting the certificate
VERISIGN_INTERMEDIATE
This is the intermediate to be used for your CA chain
VERISIGN_ROOT
This is the root to be used for your CA chain

Digicert Issuer Plugin

The following configuration properties are required to use the Digicert issuer plugin.

DIGICERT_URL
This is the url for the Digicert API (e.g. https://www.digicert.com)
DIGICERT_API_KEY
This is the Digicert API key
DIGICERT_ORG_ID
This is the Digicert organization ID tied to your API key
DIGICERT_ROOT
This is the root to be used for your CA chain
DIGICERT_DEFAULT_VALIDITY
This is the default validity (in years), if no end date is specified. (Default: 1)
DIGICERT_PRIVATE
This is whether or not to issue a private certificate. (Default: False)

CFSSL Issuer Plugin

The following configuration properties are required to use the CFSSL issuer plugin.

CFSSL_URL
This is the URL for the CFSSL API
CFSSL_ROOT
This is the root to be used for your CA chain
CFSSL_INTERMEDIATE
This is the intermediate to be used for your CA chain

AWS Source/Destination Plugin

In order for Lemur to manage its 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 TLS certificates in AWS. But is not required to do so.

Setting up IAM roles

Lemur’s AWS plugin 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 two new 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 are example policies for the LemurInstanceProfile:

SES-SendEmail

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail"
      ],
      "Resource": "*"
    }
  ]
}

STS-AssumeRole

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action":
        "sts:AssumeRole",
      "Resource": "*"
    }
  ]
}

Next we will create the Lemur IAM role.

Note

The default IAM role that Lemur assumes into is called Lemur, if you need to change this ensure you set LEMUR_INSTANCE_PROFILE to your role name in the configuration.

Here is an example policy for Lemur:

IAM-ServerCertificate

{
    "Statement": [
                {
                     "Action": [
                          "iam:ListServerCertificates",
                          "iam:UpdateServerCertificate",
                          "iam:GetServerCertificate",
                          "iam:UploadServerCertificate"
                     ],
                     "Resource": [
                          "*"
                     ],
                     "Effect": "Allow",
                     "Sid": "Stmt1404836868000"
                }
           ]
}
{
    "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:

{
  "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:

{
  "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

The configuration:

LEMUR_MAIL = 'lemur.example.com'

Will be the 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.

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

Builtin Commands

All commands default to ~/.lemur/lemur.conf.py if a configuration is not specified.

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.

init

Initializes the configuration file for Lemur.

lemur -c /etc/lemur.conf.py init
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
db upgrade

Performs any needed database migrations.

lemur db upgrade
check_revoked

Traverses every certificate that Lemur is aware of and attempts to understand its validity. It utilizes both OCSP and CRL. If Lemur is unable to come to a conclusion about a certificates validity its status is marked ‘unknown’.

sync

Sync attempts to discover certificates in the environment that were not created by Lemur. If you wish to only sync a few sources you can pass a comma delimited list of sources to sync.

lemur sync -s source1,source2

Additionally you can also list the available sources that Lemur can sync.

lemur sync
notify

Will traverse all current notifications and see if any of them need to be triggered.

lemur notify

Sub-commands

Lemur includes several sub-commands for interacting with Lemur such as creating new users, creating new roles and even issuing certificates.

The best way to discover these commands is by using the built in help pages

lemur --help

and to get help on sub-commands

lemur certificates --help

Upgrading Lemur

To upgrade Lemur to the newest release you will need to ensure you have the latest code and have run any needed database migrations.

To get the latest code from github run

cd <lemur-source-directory>
git pull -t <version>
python setup.py develop

Note

It’s important to grab the latest release by specifying the release tag. This tags denote stable versions of Lemur. If you want to try the bleeding edge version of Lemur you can by using the master branch.

After you have the latest version of the Lemur code base you must run any needed database migrations. To run migrations

cd <lemur-source-directory>/lemur
lemur db upgrade

This will ensure that any needed tables or columns are created or destroyed.

Note

Internally, this uses Alembic to manage database migrations.

Note

By default Alembic looks for the migrations folder in the current working directory.The migrations folder is located under <LEMUR_HOME>/lemur/migrations if you are running the lemur command from any location besides <LEMUR_HOME>/lemur you will need to pass the -d flag to specify the absolute file path to the migrations folder.

Plugins

There are several interfaces currently available to extend Lemur. These are a work in progress and the API is not frozen.

Lemur includes several plugins by default. Including extensive support for AWS, VeriSign/Symantec.

Verisign/Symantec

Authors:Kevin Glisson <kglisson@netflix.com>
Type:Issuer
Description:Basic support for the VICE 2.0 API

Cryptography

Authors:Kevin Glisson <kglisson@netflix.com>, Mikhail Khodorovskiy <mikhail.khodorovskiy@jivesoftware.com>
Type:Issuer
Description:Toy certificate authority that creates self-signed certificate authorities. Allows for the creation of arbitrary authorities and end-entity certificates. This is not recommended for production use.

Acme

Authors:Kevin Glisson <kglisson@netflix.com>, Mikhail Khodorovskiy <mikhail.khodorovskiy@jivesoftware.com>
Type:Issuer
Description:Adds support for the ACME protocol (including LetsEncrypt) with domain validation being handled Route53.

Atlas

Authors:Kevin Glisson <kglisson@netflix.com>
Type:Metric
Description:Adds basic support for the Atlas telemetry system.

Email

Authors:Kevin Glisson <kglisson@netflix.com>
Type:Notification
Description:Adds support for basic email notifications via SES.

Slack

Authors:Harm Weites <harm@weites.com>
Type:Notification
Description:Adds support for slack notifications.

AWS

Authors:Kevin Glisson <kglisson@netflix.com>
Type:Source
Description:Uses AWS IAM as a source of certificates to manage. Supports a multi-account deployment.

AWS

Authors:Kevin Glisson <kglisson@netflix.com>
Type:Destination
Description:Uses AWS IAM as a destination for Lemur generated certificates. Support a multi-account deployment.

Kubernetes

Authors:Mikhail Khodorovskiy <mikhail.khodorovskiy@jivesoftware.com>
Type:Destination
Description:Allows Lemur to upload generated certificates to the Kubernetes certificate store.

Java

Authors:Kevin Glisson <kglisson@netflix.com>
Type:Export
Description:Generates java compatible .jks keystores and truststores from Lemur managed certificates.

Openssl

Authors:Kevin Glisson <kglisson@netflix.com>
Type:Export
Description:Leverages Openssl to support additional export formats (pkcs12)

CFSSL

Authors:Charles Hendrie <chad.hendrie@thomsonreuters.com>
Type:Issuer
Description:Basic support for generating certificates from the private certificate authority CFSSL

3rd Party Plugins

The following plugins are available and maintained by members of the Lemur community:

Digicert

Authors:Chris Dorros
Type:Issuer
Description:Adds support for basic Digicert
Links:https://github.com/opendns/lemur-digicert

Have an extension that should be listed here? Submit a pull request and we’ll get it added.

Want to create your own extension? See Structure to get started.

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 they can be assigned one or more roles. These roles are typically dynamically created depending on an 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 are 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, 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. Owners can also be a role name, such that any user with the same role as owner will be allowed to view the private key information.

These permissions are applied to the user upon login and refreshed on every request.

See also

Flask-Principal