Backfill the key_type column: DB Upgrade
This commit is contained in:
parent
531e5c0d00
commit
8de9842092
|
@ -71,6 +71,23 @@ def parse_private_key(private_key):
|
|||
)
|
||||
|
||||
|
||||
def get_key_type_from_certificate(body):
|
||||
"""
|
||||
|
||||
Helper function to determine key type by pasrding given PEM certificate
|
||||
|
||||
:param body: PEM string
|
||||
:return: Key type string
|
||||
"""
|
||||
parsed_cert = parse_certificate(body)
|
||||
if isinstance(parsed_cert.public_key(), rsa.RSAPublicKey):
|
||||
return "RSA{key_size}".format(
|
||||
key_size=parsed_cert.public_key().key_size
|
||||
)
|
||||
elif isinstance(parsed_cert.public_key(), ec.EllipticCurvePublicKey):
|
||||
return get_key_type_from_ec_curve(parsed_cert.public_key().curve.name)
|
||||
|
||||
|
||||
def split_pem(data):
|
||||
"""
|
||||
Split a string of several PEM payloads to a list of strings.
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
"""
|
||||
|
||||
This upgrade of database updates the key_type information for certificates
|
||||
that are either still valid or have expired in last 30 days. For RSA keys,
|
||||
the algorithm is determined based on the key length. For rest of the keys,
|
||||
the certificate body is parsed to determine the exact key type information.
|
||||
|
||||
Each individual change is explicitly committed. The logs are added to file
|
||||
named upgrade_logs in current working directory. If faced any issue while
|
||||
running this upgrade, there is no harm in re-running the upgrade. Each run
|
||||
processes only the keys for which key type information is not yet determined.
|
||||
A successful end to end run will end up updating the Alembic Version to new
|
||||
Revision ID c301c59688d2. Currently only RSA and ECC certificates are supported
|
||||
by Lemur. This could be a long running job depending upon the number of
|
||||
keys it may process.
|
||||
|
||||
Revision ID: c301c59688d2
|
||||
Revises: 434c29e40511
|
||||
Create Date: 2020-09-21 14:28:50.757998
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'c301c59688d2'
|
||||
down_revision = '434c29e40511'
|
||||
|
||||
from alembic import op
|
||||
from sqlalchemy.sql import text
|
||||
from lemur.common import utils
|
||||
import time
|
||||
|
||||
log_file = open('upgrade_logs', 'a')
|
||||
|
||||
|
||||
def upgrade():
|
||||
log_file.write("\n*** Starting new run ***\n")
|
||||
start_time = time.time()
|
||||
|
||||
# Update RSA keys using the key length information
|
||||
update_key_type_rsa(1024)
|
||||
update_key_type_rsa(2048)
|
||||
update_key_type_rsa(4096)
|
||||
|
||||
# Process remaining certificates. Though below method does not make any assumptions, most of the remaining ones should be ECC certs.
|
||||
update_key_type()
|
||||
|
||||
log_file.write("--- Total %s seconds ---\n" % (time.time() - start_time))
|
||||
log_file.close()
|
||||
|
||||
|
||||
def downgrade():
|
||||
# Change key type column back to null
|
||||
# Going back 32 days instead of 31 to make sure no certificates are skipped
|
||||
stmt = text(
|
||||
"update certificates set key_type=null where not_after > CURRENT_DATE - 32"
|
||||
)
|
||||
op.execute(stmt)
|
||||
|
||||
|
||||
"""
|
||||
Helper methods performing updates for RSA and rest of the keys
|
||||
"""
|
||||
|
||||
|
||||
def update_key_type_rsa(bits):
|
||||
log_file.write("Processing certificate with key type RSA %s\n" % bits)
|
||||
|
||||
stmt = text(
|
||||
"update certificates set key_type='RSA{0}' where bits={0} and not_after > CURRENT_DATE - 31 and key_type is null".format(bits)
|
||||
)
|
||||
log_file.write("Query: %s\n" % stmt)
|
||||
|
||||
start_time = time.time()
|
||||
op.execute(stmt)
|
||||
commit()
|
||||
|
||||
log_file.write("--- %s seconds ---\n" % (time.time() - start_time))
|
||||
|
||||
|
||||
def update_key_type():
|
||||
conn = op.get_bind()
|
||||
start_time = time.time()
|
||||
|
||||
# Loop through all certificates are valid today or expired in last 30 days
|
||||
for cert_id, body in conn.execute(
|
||||
text(
|
||||
"select id, body from certificates where bits < 1024 and not_after > CURRENT_DATE - 31 and key_type is null")
|
||||
):
|
||||
try:
|
||||
cert_key_type = utils.get_key_type_from_certificate(body)
|
||||
except ValueError:
|
||||
log_file.write("Error in processing certificate. ID: %s\n" % cert_id)
|
||||
else:
|
||||
log_file.write("Processing certificate - ID: %s key_type: %s\n" % (cert_id, cert_key_type))
|
||||
stmt = text(
|
||||
"update certificates set key_type=:key_type where id=:id"
|
||||
)
|
||||
stmt = stmt.bindparams(key_type=cert_key_type, id=cert_id)
|
||||
op.execute(stmt)
|
||||
|
||||
commit()
|
||||
|
||||
log_file.write("--- %s seconds ---\n" % (time.time() - start_time))
|
||||
|
||||
|
||||
def commit():
|
||||
stmt = text("commit")
|
||||
op.execute(stmt)
|
Loading…
Reference in New Issue