Merge "Encrypt scrubber marker files"
This commit is contained in:
commit
dd6ff0e53d
@ -33,3 +33,8 @@ registry_host = 0.0.0.0
|
||||
|
||||
# Port the registry server is listening on
|
||||
registry_port = 9191
|
||||
|
||||
# AES key for encrypting store 'location' metadata, including
|
||||
# -- if used -- Swift or S3 credentials
|
||||
# Should be set to a random string of length 16, 24 or 32 bytes
|
||||
#metadata_encryption_key = <16, 24 or 32 char registry metadata key>
|
||||
|
@ -19,6 +19,7 @@ import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from glance.common import crypt
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
import glance.context
|
||||
@ -277,6 +278,8 @@ def schedule_delayed_delete_from_backend(uri, image_id, **kwargs):
|
||||
'image_id': image_id}
|
||||
raise exception.Duplicate(msg)
|
||||
|
||||
if CONF.metadata_encryption_key is not None:
|
||||
uri = crypt.urlsafe_encrypt(CONF.metadata_encryption_key, uri, 64)
|
||||
with open(file_path, 'w') as f:
|
||||
f.write('\n'.join([uri, str(int(delete_time))]))
|
||||
os.chmod(file_path, 0600)
|
||||
|
@ -20,6 +20,7 @@ import eventlet
|
||||
import os
|
||||
import time
|
||||
|
||||
from glance.common import crypt
|
||||
from glance.common import utils
|
||||
from glance import context
|
||||
from glance.openstack.common import cfg
|
||||
@ -124,6 +125,8 @@ class Scrubber(object):
|
||||
|
||||
def _delete(self, id, uri, now):
|
||||
file_path = os.path.join(self.datadir, str(id))
|
||||
if CONF.metadata_encryption_key is not None:
|
||||
uri = crypt.urlsafe_decrypt(CONF.metadata_encryption_key, uri)
|
||||
try:
|
||||
LOG.debug(_("Deleting %(uri)s") % {'uri': uri})
|
||||
# Here we create a request context with credentials to support
|
||||
|
@ -417,6 +417,7 @@ class ScrubberDaemon(Server):
|
||||
self.server_name = 'scrubber'
|
||||
self.daemon = daemon
|
||||
|
||||
self.image_dir = os.path.join(self.test_dir, "images")
|
||||
self.scrubber_datadir = os.path.join(self.test_dir,
|
||||
"scrubber")
|
||||
self.pid_file = os.path.join(self.test_dir, "scrubber.pid")
|
||||
@ -428,15 +429,18 @@ class ScrubberDaemon(Server):
|
||||
self.swift_store_container = kwargs.get("swift_store_container", "")
|
||||
self.swift_store_auth_version = kwargs.get("swift_store_auth_version",
|
||||
"2")
|
||||
self.metadata_encryption_key = "012345678901234567890123456789ab"
|
||||
self.conf_base = """[DEFAULT]
|
||||
verbose = %(verbose)s
|
||||
debug = %(debug)s
|
||||
filesystem_store_datadir=%(image_dir)s
|
||||
log_file = %(log_file)s
|
||||
daemon = %(daemon)s
|
||||
wakeup_time = 2
|
||||
scrubber_datadir = %(scrubber_datadir)s
|
||||
registry_host = 127.0.0.1
|
||||
registry_port = %(registry_port)s
|
||||
metadata_encryption_key = %(metadata_encryption_key)s
|
||||
swift_store_auth_address = %(swift_store_auth_address)s
|
||||
swift_store_user = %(swift_store_user)s
|
||||
swift_store_key = %(swift_store_key)s
|
||||
|
@ -21,6 +21,8 @@ import nose
|
||||
import os
|
||||
import time
|
||||
|
||||
from glance.common import crypt
|
||||
from glance.store.swift import StoreLocation
|
||||
from glance.tests import functional
|
||||
from glance.tests.functional.store.test_swift import parse_config
|
||||
from glance.tests.functional.store.test_swift import read_config
|
||||
@ -226,3 +228,83 @@ class TestScrubber(functional.FunctionalTest):
|
||||
self.fail('image was never scrubbed')
|
||||
|
||||
self.stop_servers()
|
||||
|
||||
def test_scrubber_with_metadata_enc(self):
|
||||
"""
|
||||
test that files written to scrubber_data_dir use
|
||||
metadata_encryption_key when available to encrypt the location
|
||||
"""
|
||||
config_path = os.environ.get('GLANCE_TEST_SWIFT_CONF')
|
||||
if not config_path:
|
||||
msg = "GLANCE_TEST_SWIFT_CONF environ not set."
|
||||
self.skipTest(msg)
|
||||
|
||||
raw_config = read_config(config_path)
|
||||
swift_config = parse_config(raw_config)
|
||||
|
||||
self.cleanup()
|
||||
self.start_servers(delayed_delete=True, daemon=True,
|
||||
default_store='swift', **swift_config)
|
||||
|
||||
# add an image
|
||||
headers = {
|
||||
'x-image-meta-name': 'test_image',
|
||||
'x-image-meta-is_public': 'true',
|
||||
'x-image-meta-disk_format': 'raw',
|
||||
'x-image-meta-container_format': 'ovf',
|
||||
'content-type': 'application/octet-stream',
|
||||
}
|
||||
path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', body='XXX',
|
||||
headers=headers)
|
||||
self.assertEqual(response.status, 201)
|
||||
image = json.loads(content)['image']
|
||||
self.assertEqual('active', image['status'])
|
||||
image_id = image['id']
|
||||
|
||||
# delete the image
|
||||
path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
|
||||
image_id)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'DELETE')
|
||||
self.assertEqual(response.status, 200)
|
||||
|
||||
response, content = http.request(path, 'HEAD')
|
||||
self.assertEqual(response.status, 200)
|
||||
self.assertEqual('pending_delete', response['x-image-meta-status'])
|
||||
|
||||
# ensure the marker file has encrypted the image location by decrypting
|
||||
# it and checking the image_id is intact
|
||||
file_path = os.path.join(self.api_server.scrubber_datadir,
|
||||
str(image_id))
|
||||
marker_uri = ''
|
||||
with open(file_path, 'r') as f:
|
||||
marker_uri = f.readline().strip()
|
||||
self.assertTrue(marker_uri is not None)
|
||||
|
||||
decrypted_uri = crypt.urlsafe_decrypt(
|
||||
self.api_server.metadata_encryption_key, marker_uri)
|
||||
loc = StoreLocation({})
|
||||
loc.parse_uri(decrypted_uri)
|
||||
|
||||
self.assertEqual("swift+http", loc.scheme)
|
||||
self.assertEqual(image['id'], loc.obj)
|
||||
|
||||
# NOTE(jkoelker) The build servers sometimes take longer than
|
||||
# 15 seconds to scrub. Give it up to 5 min, checking
|
||||
# checking every 15 seconds. When/if it flips to
|
||||
# deleted, bail immediately.
|
||||
for _ in xrange(3):
|
||||
time.sleep(5)
|
||||
|
||||
response, content = http.request(path, 'HEAD')
|
||||
if (response['x-image-meta-status'] == 'deleted' and
|
||||
response['x-image-meta-deleted'] == 'True'):
|
||||
break
|
||||
else:
|
||||
continue
|
||||
else:
|
||||
self.fail('image was never scrubbed')
|
||||
|
||||
self.stop_servers()
|
||||
|
Loading…
Reference in New Issue
Block a user