Additional work

This commit is contained in:
Curtis Castrapel 2018-04-30 10:48:48 -07:00
parent 48dde287d8
commit 3e64dd4653
8 changed files with 125 additions and 21 deletions

View File

@ -74,7 +74,14 @@ class CertificateInputSchema(CertificateCreationSchema):
dns_provider = fields.Nested(DnsProviderSchema, missing={}, required=False, allow_none=True) dns_provider = fields.Nested(DnsProviderSchema, missing={}, required=False, allow_none=True)
csr = fields.String(validate=validators.csr) csr = fields.String(validate=validators.csr)
key_type = fields.String(validate=validate.OneOf(['RSA2048', 'RSA4096']), missing='RSA2048')
key_type = fields.String(
validate=validate.OneOf(
['RSA2048', 'RSA4096', 'ECCPRIME192V1', 'ECCPRIME256V1', 'ECCSECP192R1', 'ECCSECP224R1',
'ECCSECP256R1', 'ECCSECP384R1', 'ECCSECP521R1', 'ECCSECP256K1','ECCSECT163K1', 'ECCSECT233K1',
'ECCSECT283K1', 'ECCSECT409K1', 'ECCSECT571K1', 'ECCSECT163R2', 'ECCSECT233R1', 'ECCSECT283R1',
'ECCSECT409R1', 'ECCSECT571R2']),
missing='RSA2048')
notify = fields.Boolean(default=True) notify = fields.Boolean(default=True)
rotation = fields.Boolean() rotation = fields.Boolean()

View File

@ -2,17 +2,24 @@
.. module: lemur.pending_certificates.cli .. module: lemur.pending_certificates.cli
.. moduleauthor:: James Chuong <jchuong@instartlogic.com> .. moduleauthor:: James Chuong <jchuong@instartlogic.com>
.. moduleauthor:: Curtis Castrapel <ccastrapel@netflix.com>
""" """
from flask_script import Manager from flask_script import Manager
from multiprocessing import Pool
from lemur.pending_certificates import service as pending_certificate_service from lemur.pending_certificates import service as pending_certificate_service
from lemur.plugins.base import plugins from lemur.plugins.base import plugins
from lemur.users import service as user_service from lemur.users import service as user_service
manager = Manager(usage="Handles pending certificate related tasks.") manager = Manager(usage="Handles pending certificate related tasks.")
agents = 20
# Need to call this multiple times and store status of the cert in DB. If it is being worked on by a worker, and which
# worker.
# Then open up an arbitrary number of copies of this? every minute??
# Or instead how about you send in a list of all pending certificates, make all the dns changes at once, then loop
# through and wait for each one to complete?
@manager.option('-i', dest='ids', action='append', help='IDs of pending certificates to fetch') @manager.option('-i', dest='ids', action='append', help='IDs of pending certificates to fetch')
def fetch(ids): def fetch(ids):
""" """
@ -22,10 +29,10 @@ def fetch(ids):
ids: a list of ids of PendingCertificates (passed in by manager options when run as CLI) ids: a list of ids of PendingCertificates (passed in by manager options when run as CLI)
`python manager.py pending_certs fetch -i 123 321 all` `python manager.py pending_certs fetch -i 123 321 all`
""" """
new = 0
failed = 0
pending_certs = pending_certificate_service.get_pending_certs(ids) pending_certs = pending_certificate_service.get_pending_certs(ids)
user = user_service.get_by_username('lemur') user = user_service.get_by_username('lemur')
new = 0
failed = 0
for cert in pending_certs: for cert in pending_certs:
authority = plugins.get(cert.authority.plugin_name) authority = plugins.get(cert.authority.plugin_name)
@ -43,6 +50,40 @@ def fetch(ids):
print( print(
"[+] Certificates: New: {new} Failed: {failed}".format( "[+] Certificates: New: {new} Failed: {failed}".format(
new=new, new=new,
failed=failed failed=failed,
)
)
def fetch_all():
"""
Attempt to get full certificates for each pending certificate listed.
Args:
ids: a list of ids of PendingCertificates (passed in by manager options when run as CLI)
`python manager.py pending_certs fetch -i 123 321 all`
"""
pending_certs = pending_certificate_service.get_pending_certs('all')
user = user_service.get_by_username('lemur')
new = 0
failed = 0
certs = authority.get_ordered_certificates(pending_certs)
for cert in certs:
authority = plugins.get(cert.authority.plugin_name)
real_cert = authority.get_ordered_certificate(cert)
if real_cert:
# If a real certificate was returned from issuer, then create it in Lemur and delete
# the pending certificate
pending_certificate_service.create_certificate(cert, real_cert, user)
pending_certificate_service.delete(cert)
# add metrics to metrics extension
new += 1
else:
pending_certificate_service.increment_attempt(cert)
failed += 1
print(
"[+] Certificates: New: {new} Failed: {failed}".format(
new=new,
failed=failed,
) )
) )

View File

@ -236,6 +236,49 @@ class ACMEIssuerPlugin(IssuerPlugin):
} }
return cert return cert
def get_ordered_certificates(self, pending_certs):
pending = []
for pending_cert in pending_certs:
acme_client, registration = setup_acme_client(pending_cert.authority)
order_info = authorization_service.get(pending_cert.external_id)
dns_provider = dns_provider_service.get(pending_cert.dns_provider_id)
dns_provider_type = __import__(dns_provider.provider_type, globals(), locals(), [], 1)
authorizations = get_authorizations(
acme_client, order_info.account_number, order_info.domains, dns_provider_type)
pending.append({
"acme_client": acme_client,
"account_number": order_info.account_number,
"dns_provider_type": dns_provider_type,
"authorizations": authorizations,
"pending_cert": pending_cert,
})
certs = []
for entry in pending:
finalize_authorizations(
pending["acme_client"],
pending["account_number"],
pending["dns_provider_type"],
pending["authorizations"]
)
pem_certificate, pem_certificate_chain = request_certificate(
pending["acme_client"],
pending["authorizations"],
pending["pending_cert"].csr
)
cert = {
'body': "\n".join(str(pem_certificate).splitlines()),
'chain': "\n".join(str(pem_certificate_chain).splitlines()),
'external_id': str(pending_cert.external_id)
}
certs.append({
"cert": cert,
"pending_cert": pending_cert,
})
return certs
def create_certificate(self, csr, issuer_options): def create_certificate(self, csr, issuer_options):
""" """
Creates an ACME certificate. Creates an ACME certificate.

View File

@ -23,7 +23,7 @@ pyyaml==3.12 # via aspy.yaml, pre-commit
requests-toolbelt==0.8.0 # via twine requests-toolbelt==0.8.0 # via twine
requests==2.18.4 # via requests-toolbelt, twine requests==2.18.4 # via requests-toolbelt, twine
six==1.11.0 # via cfgv, pre-commit six==1.11.0 # via cfgv, pre-commit
tqdm==4.23.0 # via twine tqdm==4.23.1 # via twine
twine==1.11.0 twine==1.11.0
urllib3==1.22 # via requests urllib3==1.22 # via requests
virtualenv==15.2.0 # via pre-commit virtualenv==15.2.0 # via pre-commit

View File

@ -11,17 +11,19 @@ alembic==0.9.9
aniso8601==3.0.0 aniso8601==3.0.0
arrow==0.12.1 arrow==0.12.1
asn1crypto==0.24.0 asn1crypto==0.24.0
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.6 boto3==1.7.10
botocore==1.10.6 botocore==1.10.10
cffi==1.11.5 cffi==1.11.5
click==6.7 click==6.7
cloudflare==2.1.0
cryptography==2.2.2 cryptography==2.2.2
docutils==0.14 docutils==0.14
flask-bcrypt==0.7.1 flask-bcrypt==0.7.1
flask-cors==3.0.3 flask-cors==3.0.4
flask-mail==0.9.1 flask-mail==0.9.1
flask-migrate==2.1.1 flask-migrate==2.1.1
flask-principal==0.4.0 flask-principal==0.4.0
@ -30,6 +32,8 @@ 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.7.1 gunicorn==19.7.1
idna==2.6 idna==2.6
imagesize==1.0.0 # via sphinx imagesize==1.0.0 # via sphinx
@ -38,13 +42,14 @@ itsdangerous==0.24
jinja2==2.10 jinja2==2.10
jmespath==0.9.3 jmespath==0.9.3
josepy==1.1.0 josepy==1.1.0
jsonlines==1.2.0
lockfile==0.12.2 lockfile==0.12.2
mako==1.0.7 mako==1.0.7
markupsafe==1.0 markupsafe==1.0
marshmallow-sqlalchemy==0.13.2 marshmallow-sqlalchemy==0.13.2
marshmallow==2.15.0 marshmallow==2.15.1
mock==2.0.0 mock==2.0.0
ndg-httpsclient==0.4.4 ndg-httpsclient==0.5.0
packaging==17.1 # via sphinx packaging==17.1 # via sphinx
paramiko==2.4.1 paramiko==2.4.1
pbr==4.0.2 pbr==4.0.2
@ -62,6 +67,7 @@ pyrfc3339==1.0
python-dateutil==2.7.2 python-dateutil==2.7.2
python-editor==1.0.3 python-editor==1.0.3
pytz==2018.4 pytz==2018.4
pyyaml==3.12
raven[flask]==6.7.0 raven[flask]==6.7.0
requests[security]==2.11.1 requests[security]==2.11.1
retrying==1.3.3 retrying==1.3.3
@ -69,7 +75,7 @@ s3transfer==0.1.13
six==1.11.0 six==1.11.0
snowballstemmer==1.2.1 # via sphinx snowballstemmer==1.2.1 # via sphinx
sphinx-rtd-theme==0.3.0 sphinx-rtd-theme==0.3.0
sphinx==1.7.3 sphinx==1.7.4
sphinxcontrib-httpdomain==1.6.1 sphinxcontrib-httpdomain==1.6.1
sphinxcontrib-websupport==1.0.1 # via sphinx sphinxcontrib-websupport==1.0.1 # via sphinx
sqlalchemy-utils==0.33.2 sqlalchemy-utils==0.33.2

View File

@ -7,9 +7,9 @@
asn1crypto==0.24.0 # via cryptography asn1crypto==0.24.0 # via cryptography
attrs==17.4.0 # via pytest attrs==17.4.0 # via pytest
aws-xray-sdk==0.95 # via moto aws-xray-sdk==0.95 # via moto
boto3==1.7.8 # via moto boto3==1.7.10 # via moto
boto==2.48.0 # via moto boto==2.48.0 # via moto
botocore==1.10.8 # via boto3, moto, s3transfer botocore==1.10.10 # 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
@ -17,12 +17,12 @@ click==6.7 # via flask
cookies==2.2.1 # via moto, responses cookies==2.2.1 # via moto, responses
coverage==4.5.1 coverage==4.5.1
cryptography==2.2.2 # via moto cryptography==2.2.2 # via moto
docker-pycreds==0.2.2 # via docker docker-pycreds==0.2.3 # via docker
docker==3.2.1 # 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.10.0
faker==0.8.13 faker==0.8.13
flask==0.12.2 # via pytest-flask flask==1.0 # via pytest-flask
freezegun==0.3.10 freezegun==0.3.10
idna==2.6 # via cryptography, requests idna==2.6 # via cryptography, requests
itsdangerous==0.24 # via flask itsdangerous==0.24 # via flask

View File

@ -3,6 +3,7 @@
acme acme
alembic-autogenerate-enums alembic-autogenerate-enums
arrow arrow
asyncpool
boto3 boto3
CloudFlare CloudFlare
cryptography cryptography
@ -16,8 +17,10 @@ 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

@ -10,17 +10,18 @@ alembic==0.9.9 # via flask-migrate
aniso8601==3.0.0 # via flask-restful aniso8601==3.0.0 # via flask-restful
arrow==0.12.1 arrow==0.12.1
asn1crypto==0.24.0 # via cryptography asn1crypto==0.24.0 # via cryptography
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.8 boto3==1.7.10
botocore==1.10.8 # via boto3, s3transfer botocore==1.10.10 # via boto3, s3transfer
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
cloudflare==2.1.0 cloudflare==2.1.0
cryptography==2.2.2 cryptography==2.2.2
docutils==0.14 # via botocore docutils==0.14 # via botocore
flask-bcrypt==0.7.1 flask-bcrypt==0.7.1
flask-cors==3.0.3 flask-cors==3.0.4
flask-mail==0.9.1 flask-mail==0.9.1
flask-migrate==2.1.1 flask-migrate==2.1.1
flask-principal==0.4.0 flask-principal==0.4.0
@ -29,10 +30,13 @@ 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.7.1 gunicorn==19.7.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
@ -41,7 +45,7 @@ lockfile==0.12.2
mako==1.0.7 # via alembic mako==1.0.7 # via alembic
markupsafe==1.0 # via jinja2, mako markupsafe==1.0 # via jinja2, mako
marshmallow-sqlalchemy==0.13.2 marshmallow-sqlalchemy==0.13.2
marshmallow==2.15.0 marshmallow==2.15.1
mock==2.0.0 # via acme mock==2.0.0 # via acme
ndg-httpsclient==0.5.0 ndg-httpsclient==0.5.0
paramiko==2.4.1 paramiko==2.4.1