Skip to content

Commit

Permalink
Enable rgw trust forwarded https when https proxy
Browse files Browse the repository at this point in the history
This option is required for server-side encryption to be allowed
if radosgw is behind a reverse proxy,
such as here when certificates are configured and apache2 is running.

ref. https://docs.ceph.com/en/latest/radosgw/encryption/

It is safe to always enable when https is configured in the charm,
because it will be securely behind the reverse proxy in the unit.
This option must not be enabled when https is not configured in the charm,
because this would allow clients to spoof headers.

Closes-Bug: #2021560
Change-Id: I940f9b2f424a3d98936b5f185bf8f87b71091317
(cherry picked from commit 541ceec)
  • Loading branch information
Samuel Walladge authored and nobuto-m committed Jun 1, 2023
1 parent 2bce537 commit 13664c1
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 11 deletions.
1 change: 1 addition & 0 deletions hooks/ceph_radosgw_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ def __call__(self):
'rgw_swift_versioning': config('rgw-swift-versioning-enabled'),
'relaxed_s3_bucket_names': config('relaxed-s3-bucket-names'),
'frontend': http_frontend,
'behind_https_proxy': https(),
}

# NOTE(dosaboy): these sections must correspond to what is supported in
Expand Down
3 changes: 3 additions & 0 deletions templates/ceph.conf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ ms bind ipv6 = true
{% endif %}
rgw swift versioning enabled = {{ rgw_swift_versioning }}
rgw relaxed s3 bucket names = {{ relaxed_s3_bucket_names }}
{% if behind_https_proxy -%}
rgw trust forwarded https = true
{% endif %}
{% if global -%}
# The following are user-provided options provided via the config-flags charm option.
# User-provided [global] section config
Expand Down
112 changes: 101 additions & 11 deletions unit_tests/test_ceph_radosgw_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def test_ctxt(self, _harelation_ids, _ctxtrelation_ids, _haconfig,


class MonContextTest(CharmTestCase):
maxDiff = None

def setUp(self):
super(MonContextTest, self).setUp(context, TO_PATCH)
Expand All @@ -95,10 +96,16 @@ def plain_list_stub(key):
else:
return []

@patch('charmhelpers.contrib.hahelpers.cluster.relation_ids')
@patch('charmhelpers.contrib.hahelpers.cluster.config_get')
@patch.object(ceph, 'config', lambda *args:
'{"client.radosgw.gateway": {"rgw init timeout": 60}}')
@patch.object(context, 'ensure_host_resolvable_v6')
def test_ctxt(self, mock_ensure_rsv_v6):
def test_ctxt(
self, mock_ensure_rsv_v6, mock_config_get, mock_relation_ids
):
mock_relation_ids.return_value = []
mock_config_get.side_effect = self.test_config.get
self.socket.gethostname.return_value = 'testhost'
mon_ctxt = context.MonContext()
addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']
Expand Down Expand Up @@ -136,7 +143,8 @@ def _relation_get(attr, unit, rid):
'frontend': 'beast',
'relaxed_s3_bucket_names': False,
'rgw_zonegroup': 'zonegroup1',
'rgw_realm': 'realmX'
'rgw_realm': 'realmX',
'behind_https_proxy': False,
}
self.assertEqual(expect, mon_ctxt())
self.assertFalse(mock_ensure_rsv_v6.called)
Expand All @@ -148,10 +156,72 @@ def _relation_get(attr, unit, rid):
self.assertEqual(expect, mon_ctxt())
self.assertTrue(mock_ensure_rsv_v6.called)

@patch('ceph_radosgw_context.https')
@patch.object(ceph, 'config', lambda *args:
'{"client.radosgw.gateway": {"rgw init timeout": 60}}')
@patch.object(context, 'ensure_host_resolvable_v6')
def test_list_of_addresses_from_ceph_proxy(self, mock_ensure_rsv_v6):
def test_ctxt_with_https_proxy(self, mock_ensure_rsv_v6, mock_https):
mock_https.return_value = True
self.socket.gethostname.return_value = 'testhost'
mon_ctxt = context.MonContext()
addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']

def _relation_get(attr, unit, rid):
if attr == 'ceph-public-address':
return addresses.pop()
elif attr == 'auth':
return 'cephx'
elif attr == 'rgw.testhost_key':
return 'testkey'
elif attr == 'fsid':
return 'testfsid'

self.relation_get.side_effect = _relation_get
self.relation_ids.return_value = ['mon:6']
self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2']
self.multisite.plain_list = self.plain_list_stub
self.determine_api_port.return_value = 70
expect = {
'auth_supported': 'cephx',
'hostname': 'testhost',
'mon_hosts': '10.5.4.1 10.5.4.2 10.5.4.3',
'old_auth': False,
'systemd_rgw': True,
'unit_public_ip': '10.255.255.255',
'use_syslog': 'false',
'loglevel': 1,
'port': 70,
'client_radosgw_gateway': {'rgw init timeout': 60},
'ipv6': False,
'rgw_zone': 'default',
'fsid': 'testfsid',
'rgw_swift_versioning': False,
'frontend': 'beast',
'relaxed_s3_bucket_names': False,
'rgw_zonegroup': 'zonegroup1',
'rgw_realm': 'realmX',
'behind_https_proxy': True,
}
self.assertEqual(expect, mon_ctxt())
self.assertFalse(mock_ensure_rsv_v6.called)

self.test_config.set('prefer-ipv6', True)
addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']
expect['ipv6'] = True
expect['port'] = "[::]:%s" % (70)
self.assertEqual(expect, mon_ctxt())
self.assertTrue(mock_ensure_rsv_v6.called)

@patch('charmhelpers.contrib.hahelpers.cluster.relation_ids')
@patch('charmhelpers.contrib.hahelpers.cluster.config_get')
@patch.object(ceph, 'config', lambda *args:
'{"client.radosgw.gateway": {"rgw init timeout": 60}}')
@patch.object(context, 'ensure_host_resolvable_v6')
def test_list_of_addresses_from_ceph_proxy(
self, mock_ensure_rsv_v6, mock_config_get, mock_relation_ids
):
mock_relation_ids.return_value = []
mock_config_get.side_effect = self.test_config.get
self.socket.gethostname.return_value = 'testhost'
mon_ctxt = context.MonContext()
addresses = ['10.5.4.1 10.5.4.2 10.5.4.3']
Expand Down Expand Up @@ -190,7 +260,8 @@ def _relation_get(attr, unit, rid):
'frontend': 'beast',
'relaxed_s3_bucket_names': False,
'rgw_zonegroup': 'zonegroup1',
'rgw_realm': 'realmX'
'rgw_realm': 'realmX',
'behind_https_proxy': False,
}
self.assertEqual(expect, mon_ctxt())
self.assertFalse(mock_ensure_rsv_v6.called)
Expand All @@ -202,19 +273,27 @@ def _relation_get(attr, unit, rid):
self.assertEqual(expect, mon_ctxt())
self.assertTrue(mock_ensure_rsv_v6.called)

@patch('charmhelpers.contrib.hahelpers.cluster.relation_ids')
@patch('charmhelpers.contrib.hahelpers.cluster.config_get')
@patch.object(ceph, 'config', lambda *args:
'{"client.radosgw.gateway": {"rgw init timeout": 60}}')
def test_ctxt_missing_data(self):
def test_ctxt_missing_data(self, mock_config_get, mock_relation_ids):
mock_relation_ids.return_value = []
mock_config_get.side_effect = self.test_config.get
self.socket.gethostname.return_value = 'testhost'
mon_ctxt = context.MonContext()
self.relation_get.return_value = None
self.relation_ids.return_value = ['mon:6']
self.related_units.return_value = ['ceph/0', 'ceph/1', 'ceph/2']
self.assertEqual({}, mon_ctxt())

@patch('charmhelpers.contrib.hahelpers.cluster.relation_ids')
@patch('charmhelpers.contrib.hahelpers.cluster.config_get')
@patch.object(ceph, 'config', lambda *args:
'{"client.radosgw.gateway": {"rgw init timeout": 60}}')
def test_ctxt_inconsistent_auths(self):
def test_ctxt_inconsistent_auths(self, mock_config_get, mock_relation_ids):
mock_relation_ids.return_value = []
mock_config_get.side_effect = self.test_config.get
self.socket.gethostname.return_value = 'testhost'
mon_ctxt = context.MonContext()
addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']
Expand Down Expand Up @@ -253,13 +332,18 @@ def _relation_get(attr, unit, rid):
'frontend': 'beast',
'relaxed_s3_bucket_names': False,
'rgw_zonegroup': 'zonegroup1',
'rgw_realm': 'realmX'
'rgw_realm': 'realmX',
'behind_https_proxy': False,
}
self.assertEqual(expect, mon_ctxt())

@patch('charmhelpers.contrib.hahelpers.cluster.relation_ids')
@patch('charmhelpers.contrib.hahelpers.cluster.config_get')
@patch.object(ceph, 'config', lambda *args:
'{"client.radosgw.gateway": {"rgw init timeout": 60}}')
def test_ctxt_consistent_auths(self):
def test_ctxt_consistent_auths(self, mock_config_get, mock_relation_ids):
mock_relation_ids.return_value = []
mock_config_get.side_effect = self.test_config.get
self.socket.gethostname.return_value = 'testhost'
mon_ctxt = context.MonContext()
addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']
Expand Down Expand Up @@ -298,7 +382,8 @@ def _relation_get(attr, unit, rid):
'frontend': 'beast',
'relaxed_s3_bucket_names': False,
'rgw_zonegroup': 'zonegroup1',
'rgw_realm': 'realmX'
'rgw_realm': 'realmX',
'behind_https_proxy': False,
}
self.assertEqual(expect, mon_ctxt())

Expand Down Expand Up @@ -360,9 +445,13 @@ def _compare_version(package, version):
_test_version = '16.2.0'
context.validate_http_frontend('beast')

@patch('charmhelpers.contrib.hahelpers.cluster.relation_ids')
@patch('charmhelpers.contrib.hahelpers.cluster.config_get')
@patch.object(ceph, 'config', lambda *args:
'{"client.radosgw.gateway": {"rgw init timeout": 60}}')
def test_ctxt_inconsistent_fsids(self):
def test_ctxt_inconsistent_fsids(self, mock_config_get, mock_relation_ids):
mock_relation_ids.return_value = []
mock_config_get.side_effect = self.test_config.get
self.socket.gethostname.return_value = 'testhost'
mon_ctxt = context.MonContext()
addresses = ['10.5.4.1', '10.5.4.2', '10.5.4.3']
Expand Down Expand Up @@ -401,7 +490,8 @@ def _relation_get(attr, unit, rid):
'frontend': 'beast',
'relaxed_s3_bucket_names': False,
'rgw_zonegroup': 'zonegroup1',
'rgw_realm': 'realmX'
'rgw_realm': 'realmX',
'behind_https_proxy': False,
}
self.assertEqual(expect, mon_ctxt())

Expand Down

0 comments on commit 13664c1

Please sign in to comment.