diff --git a/app.py b/app.py index f00d9d559..0bf65d5e7 100644 --- a/app.py +++ b/app.py @@ -8,6 +8,8 @@ from flask.ext.principal import Principal from flask.ext.login import LoginManager, UserMixin from flask.ext.mail import Mail from werkzeug.routing import BaseConverter +from jwkest.jwk import RSAKey +from Crypto.PublicKey import RSA import features @@ -42,6 +44,8 @@ OVERRIDE_CONFIG_PY_FILENAME = 'conf/stack/config.py' OVERRIDE_CONFIG_KEY = 'QUAY_OVERRIDE_CONFIG' +DOCKER_V2_SIGNINGKEY_FILENAME = 'docker_v2.pem' + app = Flask(__name__) logger = logging.getLogger(__name__) @@ -154,6 +158,13 @@ dockerfile_build_queue = WorkQueue(app.config['DOCKERFILE_BUILD_QUEUE_NAME'], tf reporter=MetricQueueReporter(metric_queue)) notification_queue = WorkQueue(app.config['NOTIFICATION_QUEUE_NAME'], tf, metric_queue=metric_queue) +# Check for a key in config. If none found, generate a new signing key for Docker V2 manifests. +_v2_key_path = os.path.join(OVERRIDE_CONFIG_DIRECTORY, DOCKER_V2_SIGNINGKEY_FILENAME) +if os.path.exists(_v2_key_path): + docker_v2_signing_key = RSAKey().load(_v2_key_path) +else: + docker_v2_signing_key = RSAKey(key=RSA.generate(2048)) + database.configure(app.config) model.config.app_config = app.config model.config.store = storage diff --git a/conf/gunicorn_local.py b/conf/gunicorn_local.py index 49a30682d..f95d85cc1 100644 --- a/conf/gunicorn_local.py +++ b/conf/gunicorn_local.py @@ -1,3 +1,5 @@ +from Crypto import Random + bind = '0.0.0.0:5000' workers = 2 worker_class = 'gevent' @@ -5,3 +7,8 @@ daemon = False logconfig = 'conf/logging_debug.conf' pythonpath = '.' preload_app = True + +def post_fork(server, worker): + # Reset the Random library to ensure it won't raise the "PID check failed." error after + # gunicorn forks. + Random.atfork() diff --git a/conf/gunicorn_registry.py b/conf/gunicorn_registry.py index 944608868..9d7f080c1 100644 --- a/conf/gunicorn_registry.py +++ b/conf/gunicorn_registry.py @@ -1,6 +1,13 @@ +from Crypto import Random + bind = 'unix:/tmp/gunicorn_registry.sock' workers = 8 worker_class = 'gevent' logconfig = 'conf/logging.conf' pythonpath = '.' preload_app = True + +def post_fork(server, worker): + # Reset the Random library to ensure it won't raise the "PID check failed." error after + # gunicorn forks. + Random.atfork() diff --git a/endpoints/v2/manifest.py b/endpoints/v2/manifest.py index b927c82d4..e6202ebae 100644 --- a/endpoints/v2/manifest.py +++ b/endpoints/v2/manifest.py @@ -9,11 +9,9 @@ import json from flask import make_response, request, url_for from collections import namedtuple, OrderedDict from jwkest.jws import SIGNER_ALGS -from jwkest.jwk import RSAKey -from Crypto.PublicKey import RSA from datetime import datetime -from app import storage +from app import storage, docker_v2_signing_key from auth.jwt_auth import process_jwt_auth from endpoints.decorators import anon_protect from endpoints.v2 import v2_bp, require_repo_read, require_repo_write @@ -332,12 +330,8 @@ def _generate_and_store_manifest(namespace, repo_name, tag_name): for parent in parents: builder.add_layer(parent.storage.checksum, __get_and_backfill_image_metadata(parent)) - # TODO, stop generating a new key every time we sign a manifest, publish our key - new_key = RSA.generate(2048) - jwk = RSAKey(key=new_key) - - manifest = builder.build(jwk) - + # Sign the manifest with our signing key. + manifest = builder.build(docker_v2_signing_key) manifest_row = model.tag.associate_generated_tag_manifest(namespace, repo_name, tag_name, manifest.digest, manifest.bytes) diff --git a/initdb.py b/initdb.py index 311c3004e..50c2f4784 100644 --- a/initdb.py +++ b/initdb.py @@ -109,7 +109,7 @@ def __create_subtree(repo, structure, creator_username, parent, tag_map): new_image = model.image.set_image_metadata(docker_image_id, repo.namespace_user.username, repo.name, str(creation_time), 'no comment', command, - v1_metadata, parent) + json.dumps(v1_metadata), parent) compressed_size = random.randrange(1, 1024 * 1024 * 1024) model.image.set_image_size(docker_image_id, repo.namespace_user.username, repo.name, diff --git a/test/registry_tests.py b/test/registry_tests.py index a59074142..9d1d03d68 100644 --- a/test/registry_tests.py +++ b/test/registry_tests.py @@ -218,7 +218,7 @@ class V1RegistryPushMixin(V1RegistryMixin): self.v1_ping() # PUT /v1/repositories/{namespace}/{repository}/ - data = [{"id": image['id']} for image in images] + data = [{"id": image_id} for image_id, _ in images.iteritems()] self.conduct('PUT', '/v1/repositories/%s/%s' % (namespace, repository), data=json.dumps(data), auth=auth, expected_code=201)