Add keystone audit middleware API logging

This commit adds Keystone audit middleware API logging to the Cinder
charm in versions Yoga and newer to allow users to configure their
environment for CADF compliance. This feature can be enabled/disabled
and is set to 'disabled' by default to avoid bloat in log files.
The logging output is configured to /var/log/apache2/cinder_error.log.
This commit builds on previous discussions:
https://github.com/juju/charm-helpers/pull/808.

Closes-Bug: 1856555
Change-Id: Ia7dbd6af2305e92eaa9a65890644c4a324ab2c65
(cherry picked from commit e25b5d38fbb0692e5fab6e7f562c974316d61abe)
This commit is contained in:
Myles Penner 2024-05-29 15:13:18 -07:00
parent 256b10782a
commit 0b1667a383
8 changed files with 260 additions and 19 deletions

View File

@ -17,8 +17,6 @@ from subprocess import (
CalledProcessError,
check_call,
check_output,
Popen,
PIPE,
)
@ -58,9 +56,7 @@ def remove_lvm_physical_volume(block_device):
:param block_device: str: Full path of block device to scrub.
'''
p = Popen(['pvremove', '-ff', block_device],
stdin=PIPE)
p.communicate(input='y\n')
check_call(['pvremove', '-ff', '--yes', block_device])
def list_lvm_volume_group(block_device):

View File

@ -9,19 +9,13 @@ def get_platform():
will be returned (which is the name of the module).
This string is used to decide which platform module should be imported.
"""
# linux_distribution is deprecated and will be removed in Python 3.7
# Warnings *not* disabled, as we certainly need to fix this.
if hasattr(platform, 'linux_distribution'):
tuple_platform = platform.linux_distribution()
current_platform = tuple_platform[0]
else:
current_platform = _get_platform_from_fs()
current_platform = _get_current_platform()
if "Ubuntu" in current_platform:
return "ubuntu"
elif "CentOS" in current_platform:
return "centos"
elif "debian" in current_platform:
elif "debian" in current_platform or "Debian" in current_platform:
# Stock Python does not detect Ubuntu and instead returns debian.
# Or at least it does in some build environments like Travis CI
return "ubuntu"
@ -36,6 +30,24 @@ def get_platform():
.format(current_platform))
def _get_current_platform():
"""Return the current platform information for the OS.
Attempts to lookup linux distribution information from the platform
module for releases of python < 3.7. For newer versions of python,
the platform is determined from the /etc/os-release file.
"""
# linux_distribution is deprecated and will be removed in Python 3.7
# Warnings *not* disabled, as we certainly need to fix this.
if hasattr(platform, 'linux_distribution'):
tuple_platform = platform.linux_distribution()
current_platform = tuple_platform[0]
else:
current_platform = _get_platform_from_fs()
return current_platform
def _get_platform_from_fs():
"""Get Platform from /etc/os-release."""
with open(os.path.join(os.sep, 'etc', 'os-release')) as fin:

View File

@ -12,6 +12,11 @@ options:
default: False
description: |
Setting this to True will allow supporting services to log to syslog.
audit-middleware:
type: boolean
default: False
description: |
Enable Keystone auditing middleware for logging API calls.
openstack-origin:
type: string
default: zed

View File

@ -167,6 +167,7 @@ CINDER_CONF_DIR = "/etc/cinder"
CINDER_CONF = '%s/cinder.conf' % CINDER_CONF_DIR
CINDER_API_CONF = '%s/api-paste.ini' % CINDER_CONF_DIR
CINDER_POLICY_JSON = '%s/policy.json' % CINDER_CONF_DIR
CINDER_AUDIT_MAP = '%s/api_audit_map.conf' % CINDER_CONF_DIR
CEPH_CONF = '/etc/ceph/ceph.conf'
HAPROXY_CONF = '/etc/haproxy/haproxy.cfg'
@ -237,18 +238,24 @@ BASE_RESOURCE_MAP = OrderedDict([
cinder_contexts.VolumeUsageAuditContext(),
context.MemcacheContext(),
cinder_contexts.SectionalConfigContext(),
cinder_contexts.LVMContext()],
cinder_contexts.LVMContext(),
context.KeystoneAuditMiddleware(service='cinder')],
'services': ['cinder-api', 'cinder-volume', 'cinder-scheduler',
'haproxy']
}),
(CINDER_API_CONF, {
'contexts': [context.IdentityServiceContext()],
'contexts': [context.IdentityServiceContext(),
context.KeystoneAuditMiddleware(service='cinder')],
'services': ['cinder-api'],
}),
(CINDER_POLICY_JSON, {
'contexts': [],
'services': ['cinder-api']
}),
(CINDER_AUDIT_MAP, {
'contexts': [context.KeystoneAuditMiddleware(service='cinder')],
'services': ['cinder-api']
}),
(ceph_config_file(), {
'contexts': [context.CephContext()],
'services': ['cinder-volume']
@ -773,7 +780,7 @@ def check_local_db_actions_complete():
# Echo notification
data = {CINDER_DB_INIT_ECHO_RKEY: init_id}
# BUG: #1928383 - clear CINDER_DB_INIT_RKEY if not the leader
if not(is_elected_leader(CLUSTER_RES)):
if not is_elected_leader(CLUSTER_RES):
data[CINDER_DB_INIT_RKEY] = None
relation_set(**data)

View File

@ -0,0 +1,101 @@
#############
# OpenStack #
#############
[composite:osapi_volume]
use = call:cinder.api:root_app_factory
/: apiversions
/healthcheck: healthcheck
/v1: openstack_volume_api_v1
/v2: openstack_volume_api_v2
/v3: openstack_volume_api_v3
[composite:openstack_volume_api_v1]
use = call:cinder.api.middleware.auth:pipeline_factory
noauth = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler noauth apiv1
{% if audit_middleware and service_name -%}
keystone = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext audit apiv1
keystone_nolimit = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext audit apiv1
{% else -%}
keystone = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv1
keystone_nolimit = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv1
{% endif %}
[composite:openstack_volume_api_v2]
use = call:cinder.api.middleware.auth:pipeline_factory
noauth = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler noauth apiv2
{% if audit_middleware and service_name -%}
keystone = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext audit apiv2
keystone_nolimit = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext audit apiv2
{% else -%}
keystone = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv2
keystone_nolimit = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv2
{% endif %}
[composite:openstack_volume_api_v3]
use = call:cinder.api.middleware.auth:pipeline_factory
noauth = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler noauth apiv3
{% if audit_middleware and service_name -%}
keystone = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext audit apiv3
keystone_nolimit = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext audit apiv3
{% else -%}
keystone = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv3
keystone_nolimit = cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv3
{% endif %}
[filter:request_id]
paste.filter_factory = oslo_middleware.request_id:RequestId.factory
[filter:http_proxy_to_wsgi]
paste.filter_factory = oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory
[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
oslo_config_project = cinder
[filter:faultwrap]
paste.filter_factory = cinder.api.middleware.fault:FaultWrapper.factory
[filter:osprofiler]
paste.filter_factory = osprofiler.web:WsgiMiddleware.factory
[filter:noauth]
paste.filter_factory = cinder.api.middleware.auth:NoAuthMiddleware.factory
[filter:sizelimit]
paste.filter_factory = oslo_middleware.sizelimit:RequestBodySizeLimiter.factory
[app:apiv1]
paste.app_factory = cinder.api.v1.router:APIRouter.factory
[app:apiv2]
paste.app_factory = cinder.api.v2.router:APIRouter.factory
[app:apiv3]
paste.app_factory = cinder.api.v3.router:APIRouter.factory
[pipeline:apiversions]
pipeline = cors http_proxy_to_wsgi faultwrap osvolumeversionapp
[app:osvolumeversionapp]
paste.app_factory = cinder.api.versions:Versions.factory
[pipeline:healthcheck]
pipeline = request_id healthcheckapp
[app:healthcheckapp]
paste.app_factory = oslo_middleware:Healthcheck.app_factory
backends = disable_by_file
disable_by_file_path = /etc/cinder/healthcheck_disable
##########
# Shared #
##########
[filter:keystonecontext]
paste.filter_factory = cinder.api.middleware.auth:CinderKeystoneContext.factory
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
{% include "section-filter-audit" %}

View File

@ -0,0 +1,28 @@
[DEFAULT]
# default target endpoint type
# should match the endpoint type defined in service catalog
target_endpoint_type = None
# map urls ending with specific text to a unique action
[custom_actions]
associate = update/associate
disassociate = update/disassociate
disassociate_all = update/disassociate_all
associations = read/list/associations
# possible end path of api requests
[path_keywords]
defaults = None
detail = None
limits = None
os-quota-specs = project
qos-specs = qos-spec
snapshots = snapshot
types = type
volumes = volume
# map endpoint type defined in service catalog to CADF typeURI
[service_endpoints]
volume = service/storage/block
volumev2 = service/storage/block
volumev3 = service/storage/block

View File

@ -0,0 +1,89 @@
###############################################################################
# [ WARNING ]
# cinder configuration file maintained by Juju
# local changes may be overwritten.
###############################################################################
[DEFAULT]
rootwrap_config = /etc/cinder/rootwrap.conf
api_paste_confg = /etc/cinder/api-paste.ini
iscsi_helper = tgtadm
verbose = {{ verbose }}
debug = {{ debug }}
use_syslog = {{ use_syslog }}
auth_strategy = keystone
state_path = /var/lib/cinder
osapi_volume_workers = {{ workers }}
{% if transport_url %}
transport_url = {{ transport_url }}
{% endif %}
{% if use_internal_endpoints -%}
swift_catalog_info = object-store:swift:internalURL
keystone_catalog_info = identity:Identity Service:internalURL
glance_catalog_info = image:glance:internalURL
nova_catalog_info = compute:Compute Service:internalURL
{% endif %}
osapi_volume_listen = {{ bind_host }}
{% if osapi_volume_listen_port -%}
osapi_volume_listen_port = {{ osapi_volume_listen_port }}
{% endif -%}
{% if glance_api_servers -%}
glance_api_servers = {{ glance_api_servers }}
{% endif -%}
{% if glance_api_version -%}
glance_api_version = {{ glance_api_version }}
{% endif -%}
{% if region -%}
os_region_name = {{ region }}
{% endif -%}
{% if user_config_flags -%}
{% for key, value in user_config_flags.items() -%}
{{ key }} = {{ value }}
{% endfor -%}
{% endif -%}
volume_usage_audit_period = {{ volume_usage_audit_period }}
{% if auth_host -%}
cinder_internal_tenant_project_id = {{ admin_tenant_id }}
{% if admin_user_id -%}
cinder_internal_tenant_user_id = {{ admin_user_id }}
{% else -%}
cinder_internal_tenant_user_id = {{ admin_user }}
{% endif -%}
{% endif -%}
{% include "parts/backends" %}
{% include "section-keystone-authtoken-mitaka" %}
{% if keystone_authtoken -%}
{% include "section-service-user" %}
{% endif -%}
{% include "parts/section-database" %}
{% include "section-oslo-messaging-rabbit-ocata" %}
{% include "section-oslo-notifications" %}
{% include "section-audit-middleware-notifications" %}
[oslo_concurrency]
lock_path = /var/lock/cinder
[keymgr]
# XXX: hack to work around http://pad.lv/1516085
# will be superseded by SRU to cinder package
encryption_auth_url = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/v3
{% include "section-oslo-middleware" %}
[nova]
{% include "parts/service-auth" %}

View File

@ -27,11 +27,14 @@ configure:
- zaza.openstack.charm_tests.vault.setup.auto_initialize
tests:
- zaza.openstack.charm_tests.cinder.tests.CinderTests
- zaza.openstack.charm_tests.cinder.tests.SecurityTests
- zaza.openstack.charm_tests.policyd.tests.CinderTests
- zaza.openstack.charm_tests.cinder.tests.CinderTests
- zaza.openstack.charm_tests.cinder.tests.SecurityTests
- zaza.openstack.charm_tests.policyd.tests.CinderTests
- zaza.openstack.charm_tests.audit.tests.KeystoneAuditMiddlewareTest
tests_options:
audit-middleware:
service: cinder
policyd:
service: cinder
force_deploy: