Merge branch 'master' into ilabun/optimize-certificates-sql
This commit is contained in:
commit
50091cca1d
|
@ -22,7 +22,7 @@ Lemur
|
||||||
Lemur manages TLS certificate creation. While not able to issue certificates itself, Lemur acts as a broker between CAs
|
Lemur manages TLS certificate creation. While not able to issue certificates itself, Lemur acts as a broker between CAs
|
||||||
and environments providing a central portal for developers to issue TLS certificates with 'sane' defaults.
|
and environments providing a central portal for developers to issue TLS certificates with 'sane' defaults.
|
||||||
|
|
||||||
It works on CPython 3.5. We deploy on Ubuntu and develop on OS X.
|
It works on Python 3.7. We deploy on Ubuntu and develop on OS X.
|
||||||
|
|
||||||
|
|
||||||
Project resources
|
Project resources
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
FROM alpine:3.8
|
||||||
|
|
||||||
|
ARG VERSION
|
||||||
|
ENV VERSION master
|
||||||
|
|
||||||
|
ENV uid 1337
|
||||||
|
ENV gid 1337
|
||||||
|
ENV user lemur
|
||||||
|
ENV group lemur
|
||||||
|
|
||||||
|
RUN addgroup -S ${group} -g ${gid} && \
|
||||||
|
adduser -D -S ${user} -G ${group} -u ${uid} && \
|
||||||
|
apk --update add python3 libldap postgresql-client nginx supervisor curl tzdata openssl bash && \
|
||||||
|
apk --update add --virtual build-dependencies \
|
||||||
|
git \
|
||||||
|
tar \
|
||||||
|
curl \
|
||||||
|
python3-dev \
|
||||||
|
npm \
|
||||||
|
bash \
|
||||||
|
musl-dev \
|
||||||
|
gcc \
|
||||||
|
autoconf \
|
||||||
|
automake \
|
||||||
|
make \
|
||||||
|
nasm \
|
||||||
|
zlib-dev \
|
||||||
|
postgresql-dev \
|
||||||
|
libressl-dev \
|
||||||
|
libffi-dev \
|
||||||
|
cyrus-sasl-dev \
|
||||||
|
openldap-dev && \
|
||||||
|
pip3 install --upgrade pip && \
|
||||||
|
pip3 install --upgrade setuptools && \
|
||||||
|
mkdir -p /home/lemur/.lemur/ && \
|
||||||
|
mkdir -p /run/nginx/ /etc/nginx/ssl/
|
||||||
|
|
||||||
|
COPY ./ /opt/lemur
|
||||||
|
WORKDIR /opt/lemur
|
||||||
|
|
||||||
|
RUN chown -R $user:$group /opt/lemur/ /home/lemur/.lemur/ && \
|
||||||
|
npm install --unsafe-perm && \
|
||||||
|
pip3 install -e . && \
|
||||||
|
node_modules/.bin/gulp build && \
|
||||||
|
node_modules/.bin/gulp package --urlContextPath=$(urlContextPath) && \
|
||||||
|
apk del build-dependencies
|
||||||
|
|
||||||
|
COPY docker/entrypoint /
|
||||||
|
COPY docker/src/lemur.conf.py /home/lemur/.lemur/lemur.conf.py
|
||||||
|
COPY docker/supervisor.conf /
|
||||||
|
COPY docker/nginx/default.conf /etc/nginx/conf.d/
|
||||||
|
COPY docker/nginx/default-ssl.conf /etc/nginx/conf.d/
|
||||||
|
|
||||||
|
RUN chmod +x /entrypoint
|
||||||
|
WORKDIR /
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=12s --timeout=12s --start-period=30s \
|
||||||
|
CMD curl --fail http://localhost:80/api/1/healthcheck | grep -q ok || exit 1
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint"]
|
||||||
|
|
||||||
|
CMD ["/usr/bin/supervisord","-c","supervisor.conf"]
|
|
@ -36,7 +36,7 @@ fi
|
||||||
# fi
|
# fi
|
||||||
|
|
||||||
echo " # Running init"
|
echo " # Running init"
|
||||||
su lemur -s /bin/bash -c "cd /opt/lemur/lemur; python3 /opt/lemur/lemur/manage.py init -p ${LEMUR_ADMIN_PASSWORD}"
|
su lemur -s /bin/bash -c "cd /opt/lemur/lemur; lemur init -p ${LEMUR_ADMIN_PASSWORD}"
|
||||||
echo " # Done"
|
echo " # Done"
|
||||||
|
|
||||||
# echo "Creating user"
|
# echo "Creating user"
|
||||||
|
@ -47,11 +47,13 @@ echo " # Done"
|
||||||
cron_notify="${CRON_NOTIFY:-"0 22 * * *"}"
|
cron_notify="${CRON_NOTIFY:-"0 22 * * *"}"
|
||||||
cron_sync="${CRON_SYNC:-"*/15 * * * *"}"
|
cron_sync="${CRON_SYNC:-"*/15 * * * *"}"
|
||||||
cron_revoked="${CRON_CHECK_REVOKED:-"0 22 * * *"}"
|
cron_revoked="${CRON_CHECK_REVOKED:-"0 22 * * *"}"
|
||||||
|
cron_reissue="${CRON_REISSUE:-"0 23 * * *"}"
|
||||||
|
|
||||||
echo " # Populating crontab"
|
echo " # Populating crontab"
|
||||||
echo "${cron_notify} lemur python3 /opt/lemur/lemur/manage.py notify expirations" > /etc/crontabs/lemur_notify
|
echo "${cron_notify} lemur notify expirations" > /etc/crontabs/lemur
|
||||||
echo "${cron_sync} lemur python3 /opt/lemur/lemur/manage.py source sync -s all" > /etc/crontabs/lemur_sync
|
echo "${cron_sync} lemur source sync -s all" >> /etc/crontabs/lemur
|
||||||
echo "${cron_revoked} lemur python3 /opt/lemur/lemur/manage.py certificate check_revoked" > /etc/crontabs/lemur_revoked
|
echo "${cron_revoked} lemur certificate check_revoked" >> /etc/crontabs/lemur
|
||||||
|
echo "${cron_reissue} lemur certificate reissue -c" >> /etc/crontabs/lemur
|
||||||
echo " # Done"
|
echo " # Done"
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
|
|
@ -16,12 +16,16 @@ LEMUR_WHITELISTED_DOMAINS = []
|
||||||
LEMUR_EMAIL = ''
|
LEMUR_EMAIL = ''
|
||||||
LEMUR_SECURITY_TEAM_EMAIL = []
|
LEMUR_SECURITY_TEAM_EMAIL = []
|
||||||
|
|
||||||
|
ALLOW_CERT_DELETION = os.environ.get('ALLOW_CERT_DELETION') == "True"
|
||||||
|
|
||||||
LEMUR_DEFAULT_COUNTRY = repr(os.environ.get('LEMUR_DEFAULT_COUNTRY',''))
|
LEMUR_DEFAULT_COUNTRY = str(os.environ.get('LEMUR_DEFAULT_COUNTRY',''))
|
||||||
LEMUR_DEFAULT_STATE = repr(os.environ.get('LEMUR_DEFAULT_STATE',''))
|
LEMUR_DEFAULT_STATE = str(os.environ.get('LEMUR_DEFAULT_STATE',''))
|
||||||
LEMUR_DEFAULT_LOCATION = repr(os.environ.get('LEMUR_DEFAULT_LOCATION',''))
|
LEMUR_DEFAULT_LOCATION = str(os.environ.get('LEMUR_DEFAULT_LOCATION',''))
|
||||||
LEMUR_DEFAULT_ORGANIZATION = repr(os.environ.get('LEMUR_DEFAULT_ORGANIZATION',''))
|
LEMUR_DEFAULT_ORGANIZATION = str(os.environ.get('LEMUR_DEFAULT_ORGANIZATION',''))
|
||||||
LEMUR_DEFAULT_ORGANIZATIONAL_UNIT = repr(os.environ.get('LEMUR_DEFAULT_ORGANIZATIONAL_UNIT',''))
|
LEMUR_DEFAULT_ORGANIZATIONAL_UNIT = str(os.environ.get('LEMUR_DEFAULT_ORGANIZATIONAL_UNIT',''))
|
||||||
|
|
||||||
|
LEMUR_DEFAULT_ISSUER_PLUGIN = str(os.environ.get('LEMUR_DEFAULT_ISSUER_PLUGIN',''))
|
||||||
|
LEMUR_DEFAULT_AUTHORITY = str(os.environ.get('LEMUR_DEFAULT_AUTHORITY',''))
|
||||||
|
|
||||||
ACTIVE_PROVIDERS = []
|
ACTIVE_PROVIDERS = []
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ pidfile = /tmp/supervisord.pid
|
||||||
|
|
||||||
[program:lemur]
|
[program:lemur]
|
||||||
environment=LEMUR_CONF=/home/lemur/.lemur/lemur.conf.py
|
environment=LEMUR_CONF=/home/lemur/.lemur/lemur.conf.py
|
||||||
command=/usr/bin/python3 manage.py start -b 0.0.0.0:8000
|
command=lemur start -b 0.0.0.0:8000
|
||||||
user=lemur
|
user=lemur
|
||||||
directory=/opt/lemur/lemur
|
directory=/opt/lemur/lemur
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
|
@ -24,6 +24,7 @@ stderr_logfile=/dev/stderr
|
||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
[program:cron]
|
[program:cron]
|
||||||
|
environment=LEMUR_CONF=/home/lemur/.lemur/lemur.conf.py
|
||||||
command=/usr/sbin/crond -f
|
command=/usr/sbin/crond -f
|
||||||
user=root
|
user=root
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
|
|
|
@ -286,6 +286,178 @@ def rotate(endpoint_name, new_certificate_name, old_certificate_name, message, c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def request_rotation_region(endpoint, new_cert, message, commit, log_data, region):
|
||||||
|
if region in endpoint.dnsname:
|
||||||
|
log_data["message"] = "Rotating endpoint in region"
|
||||||
|
request_rotation(endpoint, new_cert, message, commit)
|
||||||
|
else:
|
||||||
|
log_data["message"] = "Skipping rotation, region mismatch"
|
||||||
|
|
||||||
|
print(log_data)
|
||||||
|
current_app.logger.info(log_data)
|
||||||
|
|
||||||
|
|
||||||
|
@manager.option(
|
||||||
|
"-e",
|
||||||
|
"--endpoint",
|
||||||
|
dest="endpoint_name",
|
||||||
|
help="Name of the endpoint you wish to rotate.",
|
||||||
|
)
|
||||||
|
@manager.option(
|
||||||
|
"-n",
|
||||||
|
"--new-certificate",
|
||||||
|
dest="new_certificate_name",
|
||||||
|
help="Name of the certificate you wish to rotate to.",
|
||||||
|
)
|
||||||
|
@manager.option(
|
||||||
|
"-o",
|
||||||
|
"--old-certificate",
|
||||||
|
dest="old_certificate_name",
|
||||||
|
help="Name of the certificate you wish to rotate.",
|
||||||
|
)
|
||||||
|
@manager.option(
|
||||||
|
"-a",
|
||||||
|
"--notify",
|
||||||
|
dest="message",
|
||||||
|
action="store_true",
|
||||||
|
help="Send a rotation notification to the certificates owner.",
|
||||||
|
)
|
||||||
|
@manager.option(
|
||||||
|
"-c",
|
||||||
|
"--commit",
|
||||||
|
dest="commit",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Persist changes.",
|
||||||
|
)
|
||||||
|
@manager.option(
|
||||||
|
"-r",
|
||||||
|
"--region",
|
||||||
|
dest="region",
|
||||||
|
required=True,
|
||||||
|
help="Region in which to rotate the endpoint.",
|
||||||
|
)
|
||||||
|
def rotate_region(endpoint_name, new_certificate_name, old_certificate_name, message, commit, region):
|
||||||
|
"""
|
||||||
|
Rotates an endpoint in a defined region it if it has not already been replaced. If it has
|
||||||
|
been replaced, will use the replacement certificate for the rotation.
|
||||||
|
:param old_certificate_name: Name of the certificate you wish to rotate.
|
||||||
|
:param new_certificate_name: Name of the certificate you wish to rotate to.
|
||||||
|
:param endpoint_name: Name of the endpoint you wish to rotate.
|
||||||
|
:param message: Send a rotation notification to the certificates owner.
|
||||||
|
:param commit: Persist changes.
|
||||||
|
:param region: Region in which to rotate the endpoint.
|
||||||
|
"""
|
||||||
|
if commit:
|
||||||
|
print("[!] Running in COMMIT mode.")
|
||||||
|
|
||||||
|
print("[+] Starting endpoint rotation.")
|
||||||
|
status = FAILURE_METRIC_STATUS
|
||||||
|
|
||||||
|
log_data = {
|
||||||
|
"function": f"{__name__}.{sys._getframe().f_code.co_name}",
|
||||||
|
"region": region,
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
old_cert = validate_certificate(old_certificate_name)
|
||||||
|
new_cert = validate_certificate(new_certificate_name)
|
||||||
|
endpoint = validate_endpoint(endpoint_name)
|
||||||
|
|
||||||
|
if endpoint and new_cert:
|
||||||
|
log_data["endpoint"] = endpoint.dnsname
|
||||||
|
log_data["certificate"] = new_cert.name
|
||||||
|
request_rotation_region(endpoint, new_cert, message, commit, log_data, region)
|
||||||
|
|
||||||
|
elif old_cert and new_cert:
|
||||||
|
log_data["certificate"] = new_cert.name
|
||||||
|
log_data["certificate_old"] = old_cert.name
|
||||||
|
log_data["message"] = "Rotating endpoint from old to new cert"
|
||||||
|
print(log_data)
|
||||||
|
current_app.logger.info(log_data)
|
||||||
|
for endpoint in old_cert.endpoints:
|
||||||
|
log_data["endpoint"] = endpoint.dnsname
|
||||||
|
request_rotation_region(endpoint, new_cert, message, commit, log_data, region)
|
||||||
|
|
||||||
|
else:
|
||||||
|
log_data["message"] = "Rotating all endpoints that have new certificates available"
|
||||||
|
print(log_data)
|
||||||
|
current_app.logger.info(log_data)
|
||||||
|
all_pending_rotation_endpoints = endpoint_service.get_all_pending_rotation()
|
||||||
|
for endpoint in all_pending_rotation_endpoints:
|
||||||
|
log_data["endpoint"] = endpoint.dnsname
|
||||||
|
if region not in endpoint.dnsname:
|
||||||
|
log_data["message"] = "Skipping rotation, region mismatch"
|
||||||
|
print(log_data)
|
||||||
|
current_app.logger.info(log_data)
|
||||||
|
metrics.send(
|
||||||
|
"endpoint_rotation_region_skipped",
|
||||||
|
"counter",
|
||||||
|
1,
|
||||||
|
metric_tags={
|
||||||
|
"region": region,
|
||||||
|
"old_certificate_name": str(old_cert),
|
||||||
|
"new_certificate_name": str(endpoint.certificate.replaced[0].name),
|
||||||
|
"endpoint_name": str(endpoint.dnsname),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(endpoint.certificate.replaced) == 1:
|
||||||
|
log_data["certificate"] = endpoint.certificate.replaced[0].name
|
||||||
|
log_data["message"] = "Rotating all endpoints in region"
|
||||||
|
print(log_data)
|
||||||
|
current_app.logger.info(log_data)
|
||||||
|
request_rotation(endpoint, endpoint.certificate.replaced[0], message, commit)
|
||||||
|
status = SUCCESS_METRIC_STATUS
|
||||||
|
else:
|
||||||
|
status = FAILURE_METRIC_STATUS
|
||||||
|
log_data["message"] = "Failed to rotate endpoint due to Multiple replacement certificates found"
|
||||||
|
print(log_data)
|
||||||
|
current_app.logger.info(log_data)
|
||||||
|
|
||||||
|
metrics.send(
|
||||||
|
"endpoint_rotation_region",
|
||||||
|
"counter",
|
||||||
|
1,
|
||||||
|
metric_tags={
|
||||||
|
"status": FAILURE_METRIC_STATUS,
|
||||||
|
"old_certificate_name": str(old_cert),
|
||||||
|
"new_certificate_name": str(endpoint.certificate.replaced[0].name),
|
||||||
|
"endpoint_name": str(endpoint.dnsname),
|
||||||
|
"message": str(message),
|
||||||
|
"region": str(region),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
status = SUCCESS_METRIC_STATUS
|
||||||
|
print("[+] Done!")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
sentry.captureException(
|
||||||
|
extra={
|
||||||
|
"old_certificate_name": str(old_certificate_name),
|
||||||
|
"new_certificate_name": str(new_certificate_name),
|
||||||
|
"endpoint": str(endpoint_name),
|
||||||
|
"message": str(message),
|
||||||
|
"region": str(region),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
metrics.send(
|
||||||
|
"endpoint_rotation_region_job",
|
||||||
|
"counter",
|
||||||
|
1,
|
||||||
|
metric_tags={
|
||||||
|
"status": status,
|
||||||
|
"old_certificate_name": str(old_certificate_name),
|
||||||
|
"new_certificate_name": str(new_certificate_name),
|
||||||
|
"endpoint_name": str(endpoint_name),
|
||||||
|
"message": str(message),
|
||||||
|
"endpoint": str(globals().get("endpoint")),
|
||||||
|
"region": str(region),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@manager.option(
|
@manager.option(
|
||||||
"-o",
|
"-o",
|
||||||
"--old-certificate",
|
"--old-certificate",
|
||||||
|
|
|
@ -146,7 +146,8 @@ class CertificateInputSchema(CertificateCreationSchema):
|
||||||
data["extensions"]["subAltNames"] = {"names": []}
|
data["extensions"]["subAltNames"] = {"names": []}
|
||||||
elif not data["extensions"]["subAltNames"].get("names"):
|
elif not data["extensions"]["subAltNames"].get("names"):
|
||||||
data["extensions"]["subAltNames"]["names"] = []
|
data["extensions"]["subAltNames"]["names"] = []
|
||||||
data["extensions"]["subAltNames"]["names"] += csr_sans
|
|
||||||
|
data["extensions"]["subAltNames"]["names"] = csr_sans
|
||||||
return missing.convert_validity_years(data)
|
return missing.convert_validity_years(data)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -631,7 +631,8 @@ def certificate_reissue():
|
||||||
|
|
||||||
|
|
||||||
@celery.task(soft_time_limit=3600)
|
@celery.task(soft_time_limit=3600)
|
||||||
def certificate_rotate():
|
def certificate_rotate(**kwargs):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This celery task rotates certificates which are reissued but having endpoints attached to the replaced cert
|
This celery task rotates certificates which are reissued but having endpoints attached to the replaced cert
|
||||||
:return:
|
:return:
|
||||||
|
@ -641,6 +642,7 @@ def certificate_rotate():
|
||||||
if celery.current_task:
|
if celery.current_task:
|
||||||
task_id = celery.current_task.request.id
|
task_id = celery.current_task.request.id
|
||||||
|
|
||||||
|
region = kwargs.get("region")
|
||||||
log_data = {
|
log_data = {
|
||||||
"function": function,
|
"function": function,
|
||||||
"message": "rotating certificates",
|
"message": "rotating certificates",
|
||||||
|
@ -654,6 +656,10 @@ def certificate_rotate():
|
||||||
|
|
||||||
current_app.logger.debug(log_data)
|
current_app.logger.debug(log_data)
|
||||||
try:
|
try:
|
||||||
|
if region:
|
||||||
|
log_data["region"] = region
|
||||||
|
cli_certificate.rotate_region(None, None, None, None, True, region)
|
||||||
|
else:
|
||||||
cli_certificate.rotate(None, None, None, None, True)
|
cli_certificate.rotate(None, None, None, None, True)
|
||||||
except SoftTimeLimitExceeded:
|
except SoftTimeLimitExceeded:
|
||||||
log_data["message"] = "Certificate rotate: Time limit exceeded."
|
log_data["message"] = "Certificate rotate: Time limit exceeded."
|
||||||
|
|
|
@ -14,7 +14,7 @@ import re
|
||||||
import hvac
|
import hvac
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
|
|
||||||
from lemur.common.defaults import common_name
|
from lemur.common.defaults import common_name, country, state, location, organizational_unit, organization
|
||||||
from lemur.common.utils import parse_certificate
|
from lemur.common.utils import parse_certificate
|
||||||
from lemur.plugins.bases import DestinationPlugin
|
from lemur.plugins.bases import DestinationPlugin
|
||||||
from lemur.plugins.bases import SourcePlugin
|
from lemur.plugins.bases import SourcePlugin
|
||||||
|
@ -58,7 +58,7 @@ class VaultSourcePlugin(SourcePlugin):
|
||||||
"helpMessage": "Authentication method to use",
|
"helpMessage": "Authentication method to use",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tokenFile/VaultRole",
|
"name": "tokenFileOrVaultRole",
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"required": True,
|
"required": True,
|
||||||
"validation": "^([a-zA-Z0-9/._-]+/?)+$",
|
"validation": "^([a-zA-Z0-9/._-]+/?)+$",
|
||||||
|
@ -94,7 +94,7 @@ class VaultSourcePlugin(SourcePlugin):
|
||||||
body = ""
|
body = ""
|
||||||
url = self.get_option("vaultUrl", options)
|
url = self.get_option("vaultUrl", options)
|
||||||
auth_method = self.get_option("authenticationMethod", options)
|
auth_method = self.get_option("authenticationMethod", options)
|
||||||
auth_key = self.get_option("tokenFile/vaultRole", options)
|
auth_key = self.get_option("tokenFileOrVaultRole", options)
|
||||||
mount = self.get_option("vaultMount", options)
|
mount = self.get_option("vaultMount", options)
|
||||||
path = self.get_option("vaultPath", options)
|
path = self.get_option("vaultPath", options)
|
||||||
obj_name = self.get_option("objectName", options)
|
obj_name = self.get_option("objectName", options)
|
||||||
|
@ -185,7 +185,7 @@ class VaultDestinationPlugin(DestinationPlugin):
|
||||||
"helpMessage": "Authentication method to use",
|
"helpMessage": "Authentication method to use",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tokenFile/VaultRole",
|
"name": "tokenFileOrVaultRole",
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"required": True,
|
"required": True,
|
||||||
"validation": "^([a-zA-Z0-9/._-]+/?)+$",
|
"validation": "^([a-zA-Z0-9/._-]+/?)+$",
|
||||||
|
@ -202,15 +202,15 @@ class VaultDestinationPlugin(DestinationPlugin):
|
||||||
"name": "vaultPath",
|
"name": "vaultPath",
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"required": True,
|
"required": True,
|
||||||
"validation": "^([a-zA-Z0-9._-]+/?)+$",
|
"validation": "^(([a-zA-Z0-9._-]+|{(CN|OU|O|L|S|C)})+/?)+$",
|
||||||
"helpMessage": "Must be a valid Vault secrets path",
|
"helpMessage": "Must be a valid Vault secrets path. Support vars: {CN|OU|O|L|S|C}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "objectName",
|
"name": "objectName",
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"required": False,
|
"required": False,
|
||||||
"validation": "[0-9a-zA-Z.:_-]+",
|
"validation": "^([0-9a-zA-Z.:_-]+|{(CN|OU|O|L|S|C)})+$",
|
||||||
"helpMessage": "Name to bundle certs under, if blank use cn",
|
"helpMessage": "Name to bundle certs under, if blank use {CN}. Support vars: {CN|OU|O|L|S|C}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bundleChain",
|
"name": "bundleChain",
|
||||||
|
@ -241,11 +241,12 @@ class VaultDestinationPlugin(DestinationPlugin):
|
||||||
:param cert_chain:
|
:param cert_chain:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
cname = common_name(parse_certificate(body))
|
cert = parse_certificate(body)
|
||||||
|
cname = common_name(cert)
|
||||||
|
|
||||||
url = self.get_option("vaultUrl", options)
|
url = self.get_option("vaultUrl", options)
|
||||||
auth_method = self.get_option("authenticationMethod", options)
|
auth_method = self.get_option("authenticationMethod", options)
|
||||||
auth_key = self.get_option("tokenFile/vaultRole", options)
|
auth_key = self.get_option("tokenFileOrVaultRole", options)
|
||||||
mount = self.get_option("vaultMount", options)
|
mount = self.get_option("vaultMount", options)
|
||||||
path = self.get_option("vaultPath", options)
|
path = self.get_option("vaultPath", options)
|
||||||
bundle = self.get_option("bundleChain", options)
|
bundle = self.get_option("bundleChain", options)
|
||||||
|
@ -285,10 +286,27 @@ class VaultDestinationPlugin(DestinationPlugin):
|
||||||
|
|
||||||
client.secrets.kv.default_kv_version = api_version
|
client.secrets.kv.default_kv_version = api_version
|
||||||
|
|
||||||
if obj_name:
|
t_path = path.format(
|
||||||
path = "{0}/{1}".format(path, obj_name)
|
CN=cname,
|
||||||
else:
|
OU=organizational_unit(cert),
|
||||||
path = "{0}/{1}".format(path, cname)
|
O=organization(cert), # noqa: E741
|
||||||
|
L=location(cert),
|
||||||
|
S=state(cert),
|
||||||
|
C=country(cert)
|
||||||
|
)
|
||||||
|
if not obj_name:
|
||||||
|
obj_name = '{CN}'
|
||||||
|
|
||||||
|
f_obj_name = obj_name.format(
|
||||||
|
CN=cname,
|
||||||
|
OU=organizational_unit(cert),
|
||||||
|
O=organization(cert), # noqa: E741
|
||||||
|
L=location(cert),
|
||||||
|
S=state(cert),
|
||||||
|
C=country(cert)
|
||||||
|
)
|
||||||
|
|
||||||
|
path = "{0}/{1}".format(t_path, f_obj_name)
|
||||||
|
|
||||||
secret = get_secret(client, mount, path)
|
secret = get_secret(client, mount, path)
|
||||||
secret["data"][cname] = {}
|
secret["data"][cname] = {}
|
||||||
|
|
|
@ -33,7 +33,7 @@ readme-renderer==25.0 # via twine
|
||||||
requests-toolbelt==0.9.1 # via twine
|
requests-toolbelt==0.9.1 # via twine
|
||||||
requests==2.23.0 # via requests-toolbelt, twine
|
requests==2.23.0 # via requests-toolbelt, twine
|
||||||
secretstorage==3.1.2 # via keyring
|
secretstorage==3.1.2 # via keyring
|
||||||
six==1.14.0 # via bleach, cryptography, readme-renderer, virtualenv
|
six==1.15.0 # via bleach, cryptography, readme-renderer, virtualenv
|
||||||
toml==0.10.0 # via pre-commit
|
toml==0.10.0 # via pre-commit
|
||||||
tqdm==4.45.0 # via twine
|
tqdm==4.45.0 # via twine
|
||||||
twine==3.1.1 # via -r requirements-dev.in
|
twine==3.1.1 # via -r requirements-dev.in
|
||||||
|
|
|
@ -16,8 +16,8 @@ babel==2.8.0 # via sphinx
|
||||||
bcrypt==3.1.7 # via -r requirements.txt, flask-bcrypt, paramiko
|
bcrypt==3.1.7 # via -r requirements.txt, flask-bcrypt, paramiko
|
||||||
billiard==3.6.3.0 # via -r requirements.txt, celery
|
billiard==3.6.3.0 # via -r requirements.txt, celery
|
||||||
blinker==1.4 # via -r requirements.txt, flask-mail, flask-principal, raven
|
blinker==1.4 # via -r requirements.txt, flask-mail, flask-principal, raven
|
||||||
boto3==1.13.11 # via -r requirements.txt
|
boto3==1.13.18 # via -r requirements.txt
|
||||||
botocore==1.16.11 # via -r requirements.txt, boto3, s3transfer
|
botocore==1.16.18 # via -r requirements.txt, boto3, s3transfer
|
||||||
celery[redis]==4.4.2 # via -r requirements.txt
|
celery[redis]==4.4.2 # via -r requirements.txt
|
||||||
certifi==2020.4.5.1 # via -r requirements.txt, requests
|
certifi==2020.4.5.1 # via -r requirements.txt, requests
|
||||||
certsrv==2.1.1 # via -r requirements.txt
|
certsrv==2.1.1 # via -r requirements.txt
|
||||||
|
@ -42,7 +42,7 @@ flask-sqlalchemy==2.4.1 # via -r requirements.txt, flask-migrate
|
||||||
flask==1.1.2 # via -r requirements.txt, flask-bcrypt, flask-cors, flask-mail, flask-migrate, flask-principal, flask-restful, flask-script, flask-sqlalchemy, raven
|
flask==1.1.2 # via -r requirements.txt, flask-bcrypt, flask-cors, flask-mail, flask-migrate, flask-principal, flask-restful, flask-script, flask-sqlalchemy, raven
|
||||||
future==0.18.2 # via -r requirements.txt, cloudflare
|
future==0.18.2 # via -r requirements.txt, cloudflare
|
||||||
gunicorn==20.0.4 # via -r requirements.txt
|
gunicorn==20.0.4 # via -r requirements.txt
|
||||||
hvac==0.10.1 # via -r requirements.txt
|
hvac==0.10.3 # via -r requirements.txt
|
||||||
idna==2.9 # via -r requirements.txt, requests
|
idna==2.9 # via -r requirements.txt, requests
|
||||||
imagesize==1.2.0 # via sphinx
|
imagesize==1.2.0 # via sphinx
|
||||||
inflection==0.4.0 # via -r requirements.txt
|
inflection==0.4.0 # via -r requirements.txt
|
||||||
|
@ -87,7 +87,7 @@ requests-toolbelt==0.9.1 # via -r requirements.txt, acme
|
||||||
requests[security]==2.23.0 # via -r requirements.txt, acme, certsrv, cloudflare, hvac, requests-toolbelt, sphinx
|
requests[security]==2.23.0 # via -r requirements.txt, acme, certsrv, cloudflare, hvac, requests-toolbelt, sphinx
|
||||||
retrying==1.3.3 # via -r requirements.txt
|
retrying==1.3.3 # via -r requirements.txt
|
||||||
s3transfer==0.3.3 # via -r requirements.txt, boto3
|
s3transfer==0.3.3 # via -r requirements.txt, boto3
|
||||||
six==1.14.0 # via -r requirements.txt, acme, bcrypt, cryptography, flask-cors, flask-restful, hvac, josepy, jsonlines, packaging, pynacl, pyopenssl, python-dateutil, retrying, sphinxcontrib-httpdomain, sqlalchemy-utils
|
six==1.15.0 # via -r requirements.txt, acme, bcrypt, cryptography, flask-cors, flask-restful, hvac, josepy, jsonlines, packaging, pynacl, pyopenssl, python-dateutil, retrying, sphinxcontrib-httpdomain, sqlalchemy-utils
|
||||||
snowballstemmer==2.0.0 # via sphinx
|
snowballstemmer==2.0.0 # via sphinx
|
||||||
sphinx-rtd-theme==0.4.3 # via -r requirements-docs.in
|
sphinx-rtd-theme==0.4.3 # via -r requirements-docs.in
|
||||||
sphinx==3.0.3 # via -r requirements-docs.in, sphinx-rtd-theme, sphinxcontrib-httpdomain
|
sphinx==3.0.3 # via -r requirements-docs.in, sphinx-rtd-theme, sphinxcontrib-httpdomain
|
||||||
|
@ -98,7 +98,7 @@ sphinxcontrib-httpdomain==1.7.0 # via -r requirements-docs.in
|
||||||
sphinxcontrib-jsmath==1.0.1 # via sphinx
|
sphinxcontrib-jsmath==1.0.1 # via sphinx
|
||||||
sphinxcontrib-qthelp==1.0.3 # via sphinx
|
sphinxcontrib-qthelp==1.0.3 # via sphinx
|
||||||
sphinxcontrib-serializinghtml==1.1.4 # via sphinx
|
sphinxcontrib-serializinghtml==1.1.4 # via sphinx
|
||||||
sqlalchemy-utils==0.36.5 # via -r requirements.txt
|
sqlalchemy-utils==0.36.6 # via -r requirements.txt
|
||||||
sqlalchemy==1.3.16 # via -r requirements.txt, alembic, flask-sqlalchemy, marshmallow-sqlalchemy, sqlalchemy-utils
|
sqlalchemy==1.3.16 # via -r requirements.txt, alembic, flask-sqlalchemy, marshmallow-sqlalchemy, sqlalchemy-utils
|
||||||
tabulate==0.8.7 # via -r requirements.txt
|
tabulate==0.8.7 # via -r requirements.txt
|
||||||
twofish==0.3.0 # via -r requirements.txt, pyjks
|
twofish==0.3.0 # via -r requirements.txt, pyjks
|
||||||
|
|
|
@ -10,9 +10,9 @@ aws-sam-translator==1.22.0 # via cfn-lint
|
||||||
aws-xray-sdk==2.5.0 # via moto
|
aws-xray-sdk==2.5.0 # via moto
|
||||||
bandit==1.6.2 # via -r requirements-tests.in
|
bandit==1.6.2 # via -r requirements-tests.in
|
||||||
black==19.10b0 # via -r requirements-tests.in
|
black==19.10b0 # via -r requirements-tests.in
|
||||||
boto3==1.13.11 # via aws-sam-translator, moto
|
boto3==1.13.18 # via aws-sam-translator, moto
|
||||||
boto==2.49.0 # via moto
|
boto==2.49.0 # via moto
|
||||||
botocore==1.16.11 # via aws-xray-sdk, boto3, moto, s3transfer
|
botocore==1.16.18 # via aws-xray-sdk, boto3, moto, s3transfer
|
||||||
certifi==2020.4.5.1 # via requests
|
certifi==2020.4.5.1 # via requests
|
||||||
cffi==1.14.0 # via cryptography
|
cffi==1.14.0 # via cryptography
|
||||||
cfn-lint==0.29.5 # via moto
|
cfn-lint==0.29.5 # via moto
|
||||||
|
@ -72,7 +72,7 @@ requests==2.23.0 # via docker, moto, requests-mock, responses
|
||||||
responses==0.10.12 # via moto
|
responses==0.10.12 # via moto
|
||||||
rsa==4.0 # via python-jose
|
rsa==4.0 # via python-jose
|
||||||
s3transfer==0.3.3 # via boto3
|
s3transfer==0.3.3 # via boto3
|
||||||
six==1.14.0 # via aws-sam-translator, bandit, cfn-lint, cryptography, docker, ecdsa, fakeredis, freezegun, jsonschema, moto, packaging, pyrsistent, python-dateutil, python-jose, requests-mock, responses, stevedore, websocket-client
|
six==1.15.0 # via aws-sam-translator, bandit, cfn-lint, cryptography, docker, ecdsa, fakeredis, freezegun, jsonschema, moto, packaging, pyrsistent, python-dateutil, python-jose, requests-mock, responses, stevedore, websocket-client
|
||||||
smmap==3.0.2 # via gitdb
|
smmap==3.0.2 # via gitdb
|
||||||
sortedcontainers==2.1.0 # via fakeredis
|
sortedcontainers==2.1.0 # via fakeredis
|
||||||
sshpubkeys==3.1.0 # via moto
|
sshpubkeys==3.1.0 # via moto
|
||||||
|
|
|
@ -14,8 +14,8 @@ asyncpool==1.0 # via -r requirements.in
|
||||||
bcrypt==3.1.7 # via flask-bcrypt, paramiko
|
bcrypt==3.1.7 # via flask-bcrypt, paramiko
|
||||||
billiard==3.6.3.0 # via celery
|
billiard==3.6.3.0 # via celery
|
||||||
blinker==1.4 # via flask-mail, flask-principal, raven
|
blinker==1.4 # via flask-mail, flask-principal, raven
|
||||||
boto3==1.13.11 # via -r requirements.in
|
boto3==1.13.18 # via -r requirements.in
|
||||||
botocore==1.16.11 # via -r requirements.in, boto3, s3transfer
|
botocore==1.16.18 # via -r requirements.in, boto3, s3transfer
|
||||||
celery[redis]==4.4.2 # via -r requirements.in
|
celery[redis]==4.4.2 # via -r requirements.in
|
||||||
certifi==2020.4.5.1 # via -r requirements.in, requests
|
certifi==2020.4.5.1 # via -r requirements.in, requests
|
||||||
certsrv==2.1.1 # via -r requirements.in
|
certsrv==2.1.1 # via -r requirements.in
|
||||||
|
@ -40,7 +40,7 @@ flask-sqlalchemy==2.4.1 # via -r requirements.in, flask-migrate
|
||||||
flask==1.1.2 # via -r requirements.in, flask-bcrypt, flask-cors, flask-mail, flask-migrate, flask-principal, flask-restful, flask-script, flask-sqlalchemy, raven
|
flask==1.1.2 # via -r requirements.in, flask-bcrypt, flask-cors, flask-mail, flask-migrate, flask-principal, flask-restful, flask-script, flask-sqlalchemy, raven
|
||||||
future==0.18.2 # via -r requirements.in, cloudflare
|
future==0.18.2 # via -r requirements.in, cloudflare
|
||||||
gunicorn==20.0.4 # via -r requirements.in
|
gunicorn==20.0.4 # via -r requirements.in
|
||||||
hvac==0.10.1 # via -r requirements.in
|
hvac==0.10.3 # via -r requirements.in
|
||||||
idna==2.9 # via requests
|
idna==2.9 # via requests
|
||||||
inflection==0.4.0 # via -r requirements.in
|
inflection==0.4.0 # via -r requirements.in
|
||||||
itsdangerous==1.1.0 # via flask
|
itsdangerous==1.1.0 # via flask
|
||||||
|
@ -81,8 +81,8 @@ requests-toolbelt==0.9.1 # via acme
|
||||||
requests[security]==2.23.0 # via -r requirements.in, acme, certsrv, cloudflare, hvac, requests-toolbelt
|
requests[security]==2.23.0 # via -r requirements.in, acme, certsrv, cloudflare, hvac, requests-toolbelt
|
||||||
retrying==1.3.3 # via -r requirements.in
|
retrying==1.3.3 # via -r requirements.in
|
||||||
s3transfer==0.3.3 # via boto3
|
s3transfer==0.3.3 # via boto3
|
||||||
six==1.14.0 # via -r requirements.in, acme, bcrypt, cryptography, flask-cors, flask-restful, hvac, josepy, jsonlines, pynacl, pyopenssl, python-dateutil, retrying, sqlalchemy-utils
|
six==1.15.0 # via -r requirements.in, acme, bcrypt, cryptography, flask-cors, flask-restful, hvac, josepy, jsonlines, pynacl, pyopenssl, python-dateutil, retrying, sqlalchemy-utils
|
||||||
sqlalchemy-utils==0.36.5 # via -r requirements.in
|
sqlalchemy-utils==0.36.6 # via -r requirements.in
|
||||||
sqlalchemy==1.3.16 # via alembic, flask-sqlalchemy, marshmallow-sqlalchemy, sqlalchemy-utils
|
sqlalchemy==1.3.16 # via alembic, flask-sqlalchemy, marshmallow-sqlalchemy, sqlalchemy-utils
|
||||||
tabulate==0.8.7 # via -r requirements.in
|
tabulate==0.8.7 # via -r requirements.in
|
||||||
twofish==0.3.0 # via pyjks
|
twofish==0.3.0 # via pyjks
|
||||||
|
|
Loading…
Reference in New Issue