0.7 release

This commit is contained in:
Curtis Castrapel 2018-05-07 09:58:24 -07:00
parent 1be3f8368f
commit e68b3d2cbd
17 changed files with 72 additions and 63 deletions

View File

@ -2,12 +2,34 @@ Changelog
========= =========
0.7 - `master` 0.7 - `2018-05-07`
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
.. note:: This version is not yet released and is under active development This release adds LetsEncrypt support with DNS providers Dyn, Route53, and Cloudflare, and expands on the pending certificate functionality.
The pending_dns_authorizations and dns_providers tables were created. New columns
were added to the certificates and pending_certificates tables, (For the DNS provider ID), and authorities (For options).
Please run a database migration when upgrading.
The Let's Encrypt flow will run asynchronously. When a certificate is requested through the acme-issuer, a pending certificate
will be created. A cron needs to be defined to run `lemur pending_certs fetch_all_acme`. This command will iterate through all of the pending
certificates, request a DNS challenge token from Let's Encrypt, and set the appropriate _acme-challenge TXT entry. It will
then iterate through and resolve the challenges before requesting a certificate for each pending certificate. If a certificate
is successfully obtained, the pending_certificate will be moved to the certificates table with the appropriate properties.
Special thanks to all who helped with this release, notably:
- The folks at Cloudflare
- dmitryzykov
- jchuong
- seils
- titouanc
Upgrading
---------
.. note:: This release will need a migration change. Please follow the `documentation <https://lemur.readthedocs.io/en/latest/administration.html#upgrading-lemur>`_ to upgrade Lemur.
0.6 - `2018-01-02` 0.6 - `2018-01-02`
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~

View File

@ -9,7 +9,7 @@ __title__ = "lemur"
__summary__ = ("Certificate management and orchestration service") __summary__ = ("Certificate management and orchestration service")
__uri__ = "https://github.com/Netflix/lemur" __uri__ = "https://github.com/Netflix/lemur"
__version__ = "0.7.0dev" __version__ = "0.7.0"
__author__ = "The Lemur developers" __author__ = "The Lemur developers"
__email__ = "security@netflix.com" __email__ = "security@netflix.com"

View File

@ -9,6 +9,17 @@ from flask import current_app
from marshmallow import fields, validate, validates_schema, post_load, pre_load from marshmallow import fields, validate, validates_schema, post_load, pre_load
from marshmallow.exceptions import ValidationError from marshmallow.exceptions import ValidationError
from lemur.authorities.schemas import AuthorityNestedOutputSchema
from lemur.common import validators, missing
from lemur.common.fields import ArrowDateTime, Hex
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.constants import CERTIFICATE_KEY_TYPES
from lemur.destinations.schemas import DestinationNestedOutputSchema
from lemur.domains.schemas import DomainNestedOutputSchema
from lemur.notifications import service as notification_service
from lemur.notifications.schemas import NotificationNestedOutputSchema
from lemur.policies.schemas import RotationPolicyNestedOutputSchema
from lemur.roles.schemas import RoleNestedOutputSchema
from lemur.schemas import ( from lemur.schemas import (
AssociatedAuthoritySchema, AssociatedAuthoritySchema,
AssociatedDestinationSchema, AssociatedDestinationSchema,
@ -21,20 +32,7 @@ from lemur.schemas import (
AssociatedRotationPolicySchema, AssociatedRotationPolicySchema,
DnsProviderSchema DnsProviderSchema
) )
from lemur.authorities.schemas import AuthorityNestedOutputSchema
from lemur.destinations.schemas import DestinationNestedOutputSchema
from lemur.notifications.schemas import NotificationNestedOutputSchema
from lemur.roles.schemas import RoleNestedOutputSchema
from lemur.domains.schemas import DomainNestedOutputSchema
from lemur.users.schemas import UserNestedOutputSchema from lemur.users.schemas import UserNestedOutputSchema
from lemur.policies.schemas import RotationPolicyNestedOutputSchema
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.common import validators, missing
from lemur.notifications import service as notification_service
from lemur.common.fields import ArrowDateTime, Hex
class CertificateSchema(LemurInputSchema): class CertificateSchema(LemurInputSchema):
@ -76,11 +74,7 @@ class CertificateInputSchema(CertificateCreationSchema):
csr = fields.String(validate=validators.csr) csr = fields.String(validate=validators.csr)
key_type = fields.String( key_type = fields.String(
validate=validate.OneOf( validate=validate.OneOf(CERTIFICATE_KEY_TYPES),
['RSA2048', 'RSA4096', 'ECCPRIME192V1', 'ECCPRIME256V1', 'ECCSECP192R1', 'ECCSECP224R1',
'ECCSECP256R1', 'ECCSECP384R1', 'ECCSECP521R1', 'ECCSECP256K1', 'ECCSECT163K1', 'ECCSECT233K1',
'ECCSECT283K1', 'ECCSECT409K1', 'ECCSECT571K1', 'ECCSECT163R2', 'ECCSECT233R1', 'ECCSECT283R1',
'ECCSECT409R1', 'ECCSECT571R2']),
missing='RSA2048') missing='RSA2048')
notify = fields.Boolean(default=True) notify = fields.Boolean(default=True)

View File

@ -6,17 +6,15 @@
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com> .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
""" """
import string
import random import random
import string
import sqlalchemy import sqlalchemy
from sqlalchemy import and_, func
from cryptography import x509 from cryptography import x509
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa, ec from cryptography.hazmat.primitives.asymmetric import rsa, ec
from flask_restful.reqparse import RequestParser from flask_restful.reqparse import RequestParser
from sqlalchemy import and_, func
from lemur.constants import CERTIFICATE_KEY_TYPES from lemur.constants import CERTIFICATE_KEY_TYPES
from lemur.exceptions import InvalidConfiguration from lemur.exceptions import InvalidConfiguration

View File

@ -4,6 +4,7 @@ from sqlalchemy_utils import ArrowType
from lemur.database import db from lemur.database import db
from lemur.plugins.base import plugins from lemur.plugins.base import plugins
from lemur.utils import Vault
class DnsProviders(db.Model): class DnsProviders(db.Model):
@ -15,7 +16,7 @@ class DnsProviders(db.Model):
name = Column(String(length=256), unique=True, nullable=True) name = Column(String(length=256), unique=True, nullable=True)
description = Column(String(length=1024), nullable=True) description = Column(String(length=1024), nullable=True)
provider_type = Column(String(length=256), nullable=True) provider_type = Column(String(length=256), nullable=True)
credentials = Column(String(length=256), nullable=True) credentials = Column(Vault, nullable=True)
api_endpoint = Column(String(length=256), nullable=True) api_endpoint = Column(String(length=256), nullable=True)
date_created = Column(ArrowType(), server_default=text('now()'), nullable=False) date_created = Column(ArrowType(), server_default=text('now()'), nullable=False)
status = Column(String(length=128), nullable=True) status = Column(String(length=128), nullable=True)

View File

@ -55,7 +55,7 @@ certificate_replacement_associations = db.Table('certificate_replacement_associa
ForeignKey('certificates.id', ondelete='cascade')) ForeignKey('certificates.id', ondelete='cascade'))
) )
Index('certificate_replacement_associations_ix', certificate_replacement_associations.c.replaced_certificate_id, certificate_replacement_associations.c.certificate_id) Index('certificate_replacement_associations_ix', certificate_replacement_associations.c.replaced_certificate_id, certificate_replacement_associations.c.certificate_id, unique=True)
roles_authorities = db.Table('roles_authorities', roles_authorities = db.Table('roles_authorities',
Column('authority_id', Integer, ForeignKey('authorities.id')), Column('authority_id', Integer, ForeignKey('authorities.id')),

View File

@ -1,6 +1,6 @@
import time import time
import CloudFlare
import CloudFlare
from flask import current_app from flask import current_app

View File

@ -1,7 +1,7 @@
import dns.exception
import dns.resolver
import time import time
import dns.exception
import dns.resolver
from dyn.tm.session import DynectSession from dyn.tm.session import DynectSession
from dyn.tm.zones import Node, Zone from dyn.tm.zones import Node, Zone
from flask import current_app from flask import current_app

View File

@ -11,25 +11,22 @@
.. moduleauthor:: Mikhail Khodorovskiy <mikhail.khodorovskiy@jivesoftware.com> .. moduleauthor:: Mikhail Khodorovskiy <mikhail.khodorovskiy@jivesoftware.com>
.. moduleauthor:: Curtis Castrapel <ccastrapel@netflix.com> .. moduleauthor:: Curtis Castrapel <ccastrapel@netflix.com>
""" """
import josepy as jose
import json import json
from flask import current_app import OpenSSL.crypto
import josepy as jose
from acme.client import Client
from acme import challenges, messages from acme import challenges, messages
from acme.client import Client
from acme.errors import PollError from acme.errors import PollError
from botocore.exceptions import ClientError from botocore.exceptions import ClientError
from flask import current_app
from lemur.common.utils import generate_private_key
import OpenSSL.crypto
from lemur.authorizations import service as authorization_service from lemur.authorizations import service as authorization_service
from lemur.common.utils import generate_private_key
from lemur.dns_providers import service as dns_provider_service from lemur.dns_providers import service as dns_provider_service
from lemur.exceptions import InvalidAuthority, InvalidConfiguration from lemur.exceptions import InvalidAuthority, InvalidConfiguration
from lemur.plugins.bases import IssuerPlugin
from lemur.plugins import lemur_acme as acme from lemur.plugins import lemur_acme as acme
from lemur.plugins.bases import IssuerPlugin
def find_dns_challenge(authz): def find_dns_challenge(authz):

View File

@ -1,4 +1,5 @@
import time import time
from lemur.plugins.lemur_aws.sts import sts_client from lemur.plugins.lemur_aws.sts import sts_client

View File

@ -1,8 +1,9 @@
import unittest import unittest
from lemur.plugins.lemur_acme import plugin
from mock import MagicMock, Mock, patch from mock import MagicMock, Mock, patch
from lemur.plugins.lemur_acme import plugin
class TestAcme(unittest.TestCase): class TestAcme(unittest.TestCase):

View File

@ -6,12 +6,12 @@
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com> .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
""" """
import os import os
from flask import current_app
from cryptography.fernet import Fernet, MultiFernet
import sqlalchemy.types as types
from contextlib import contextmanager
import tempfile import tempfile
from contextlib import contextmanager
import sqlalchemy.types as types
from cryptography.fernet import Fernet, MultiFernet
from flask import current_app
@contextmanager @contextmanager

View File

@ -10,7 +10,7 @@ certifi==2018.4.16 # via requests
cfgv==1.0.0 # via pre-commit cfgv==1.0.0 # via pre-commit
chardet==3.0.4 # via requests chardet==3.0.4 # via requests
flake8==3.5.0 flake8==3.5.0
identify==1.0.13 # via pre-commit identify==1.0.15 # via pre-commit
idna==2.6 # via requests idna==2.6 # via requests
invoke==0.23.0 invoke==0.23.0
mccabe==0.6.1 # via flake8 mccabe==0.6.1 # via flake8

View File

@ -4,7 +4,7 @@
# #
# pip-compile --no-index --output-file requirements-docs.txt requirements-docs.in # pip-compile --no-index --output-file requirements-docs.txt requirements-docs.in
# #
acme==0.23.0 acme==0.24.0
alabaster==0.7.10 # via sphinx alabaster==0.7.10 # via sphinx
alembic-autogenerate-enums==0.0.2 alembic-autogenerate-enums==0.0.2
alembic==0.9.9 alembic==0.9.9
@ -15,13 +15,15 @@ asyncpool==1.0
babel==2.5.3 # via sphinx babel==2.5.3 # via sphinx
bcrypt==3.1.4 bcrypt==3.1.4
blinker==1.4 blinker==1.4
boto3==1.7.11 boto3==1.7.14
botocore==1.10.11 botocore==1.10.14
certifi==2018.4.16 certifi==2018.4.16
cffi==1.11.5 cffi==1.11.5
click==6.7 click==6.7
cloudflare==2.1.0 cloudflare==2.1.0
cryptography==2.2.2 cryptography==2.2.2
dnspython3==1.15.0
dnspython==1.15.0
docutils==0.14 docutils==0.14
dyn==1.8.1 dyn==1.8.1
flask-bcrypt==0.7.1 flask-bcrypt==0.7.1
@ -34,14 +36,11 @@ flask-script==2.0.6
flask-sqlalchemy==2.3.2 flask-sqlalchemy==2.3.2
flask==0.12 flask==0.12
future==0.16.0 future==0.16.0
gevent==1.2.2
greenlet==0.4.13
gunicorn==19.8.1 gunicorn==19.8.1
idna==2.6 idna==2.6
imagesize==1.0.0 # via sphinx imagesize==1.0.0 # via sphinx
inflection==0.3.1 inflection==0.3.1
itsdangerous==0.24 itsdangerous==0.24
janus==0.3.1
jinja2==2.10 jinja2==2.10
jmespath==0.9.3 jmespath==0.9.3
josepy==1.1.0 josepy==1.1.0
@ -84,5 +83,6 @@ sphinxcontrib-websupport==1.0.1 # via sphinx
sqlalchemy-utils==0.33.3 sqlalchemy-utils==0.33.3
sqlalchemy==1.2.7 sqlalchemy==1.2.7
tabulate==0.8.2 tabulate==0.8.2
tld==0.7.10
werkzeug==0.14.1 werkzeug==0.14.1
xmltodict==0.11.0 xmltodict==0.11.0

View File

@ -5,11 +5,11 @@
# pip-compile --no-index --output-file requirements-tests.txt requirements-tests.in # pip-compile --no-index --output-file requirements-tests.txt requirements-tests.in
# #
asn1crypto==0.24.0 # via cryptography asn1crypto==0.24.0 # via cryptography
attrs==17.4.0 # via pytest attrs==18.1.0 # via pytest
aws-xray-sdk==0.95 # via moto aws-xray-sdk==0.95 # via moto
boto3==1.7.11 # via moto boto3==1.7.14 # via moto
boto==2.48.0 # via moto boto==2.48.0 # via moto
botocore==1.10.11 # via boto3, moto, s3transfer botocore==1.10.14 # via boto3, moto, s3transfer
certifi==2018.4.16 # via requests certifi==2018.4.16 # via requests
cffi==1.11.5 # via cryptography cffi==1.11.5 # via cryptography
chardet==3.0.4 # via requests chardet==3.0.4 # via requests
@ -20,7 +20,7 @@ cryptography==2.2.2 # via moto
docker-pycreds==0.2.3 # via docker docker-pycreds==0.2.3 # via docker
docker==3.3.0 # via moto docker==3.3.0 # via moto
docutils==0.14 # via botocore docutils==0.14 # via botocore
factory-boy==2.10.0 factory-boy==2.11.1
faker==0.8.13 faker==0.8.13
flask==1.0.2 # via pytest-flask flask==1.0.2 # via pytest-flask
freezegun==0.3.10 freezegun==0.3.10

View File

@ -20,10 +20,8 @@ Flask-SQLAlchemy
Flask==0.12 Flask==0.12
Flask-Cors Flask-Cors
future future
gevent
gunicorn gunicorn
inflection inflection
janus
jinja2 jinja2
lockfile lockfile
marshmallow-sqlalchemy marshmallow-sqlalchemy

View File

@ -13,8 +13,8 @@ asn1crypto==0.24.0 # via cryptography
asyncpool==1.0 asyncpool==1.0
bcrypt==3.1.4 # via flask-bcrypt, paramiko bcrypt==3.1.4 # via flask-bcrypt, paramiko
blinker==1.4 # via flask-mail, flask-principal, raven blinker==1.4 # via flask-mail, flask-principal, raven
boto3==1.7.11 boto3==1.7.14
botocore==1.10.11 # via boto3, s3transfer botocore==1.10.14 # via boto3, s3transfer
certifi==2018.4.16 certifi==2018.4.16
cffi==1.11.5 # via bcrypt, cryptography, pynacl cffi==1.11.5 # via bcrypt, cryptography, pynacl
click==6.7 # via flask click==6.7 # via flask
@ -34,13 +34,10 @@ flask-script==2.0.6
flask-sqlalchemy==2.3.2 flask-sqlalchemy==2.3.2
flask==0.12 flask==0.12
future==0.16.0 future==0.16.0
gevent==1.2.2
greenlet==0.4.13 # via gevent
gunicorn==19.8.1 gunicorn==19.8.1
idna==2.6 # via cryptography idna==2.6 # via cryptography
inflection==0.3.1 inflection==0.3.1
itsdangerous==0.24 # via flask itsdangerous==0.24 # via flask
janus==0.3.1
jinja2==2.10 jinja2==2.10
jmespath==0.9.3 # via boto3, botocore jmespath==0.9.3 # via boto3, botocore
josepy==1.1.0 # via acme josepy==1.1.0 # via acme