Skip to content

Commit

Permalink
Add keystone audit middleware API logging
Browse files Browse the repository at this point in the history
This commit adds Keystone audit middleware API logging to the Nova-
Cloud-Contoller 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 writes to
/var/log/nova/nova-api-wsgi.log.
This commit builds on previous discussions:
juju/charm-helpers#808.

Closes-Bug: 1856555
Change-Id: Ie09cc6775c13a2dba6a0f3d69a4a080f9fc484c8
(cherry picked from commit 723515f)
  • Loading branch information
MylesJP committed Jun 25, 2024
1 parent 529baa3 commit cd97750
Show file tree
Hide file tree
Showing 6 changed files with 554 additions and 13 deletions.
31 changes: 18 additions & 13 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: yoga
Expand Down Expand Up @@ -187,7 +192,7 @@ options:
the nova-cloud-controller serving the request to be used.
console-keymap:
type: string
default: 'en-us'
default: "en-us"
description: |
Console keymap.
console-ssl-cert:
Expand Down Expand Up @@ -224,18 +229,18 @@ options:
type: boolean
default: True
description: |
Enable new nova-compute services on this host automatically.
When a new nova-compute service starts up, it gets registered in the
database as an enabled service. Sometimes it can be useful to register
new compute services in disabled state and then enabled them at a later
point in time. This option only sets this behavior for nova-compute
services, it does not auto-disable other services like nova-conductor,
nova-scheduler, nova-consoleauth, or nova-osapi_compute.
Possible values: True: Each new compute service is enabled as soon as
it registers itself. False: Compute services must be enabled via an
os-services REST API call or with the CLI with
nova service-enable <hostname> <binary>, otherwise they are not ready
to use.
Enable new nova-compute services on this host automatically.
When a new nova-compute service starts up, it gets registered in the
database as an enabled service. Sometimes it can be useful to register
new compute services in disabled state and then enabled them at a later
point in time. This option only sets this behavior for nova-compute
services, it does not auto-disable other services like nova-conductor,
nova-scheduler, nova-consoleauth, or nova-osapi_compute.
Possible values: True: Each new compute service is enabled as soon as
it registers itself. False: Compute services must be enabled via an
os-services REST API call or with the CLI with
nova service-enable <hostname> <binary>, otherwise they are not ready
to use.
worker-multiplier:
type: float
default:
Expand Down
13 changes: 13 additions & 0 deletions hooks/nova_cc_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
]

AWS_COMPAT_SERVICES = ['nova-api-ec2', 'nova-objectstore']
AUDIT_SERVICES = ['nova-api-os-compute']
SERVICE_BLACKLIST = {
'liberty': AWS_COMPAT_SERVICES,
'newton': ['nova-cert'],
Expand Down Expand Up @@ -286,6 +287,18 @@ def resource_map(actual_services=True):
ssl_dir=NOVA_CONF_DIR)
)

if cmp_os_release >= 'yoga':
# Conditionally render audit middleware for yoga and later
NOVA_AUDIT_MAP = '%s/api_audit_map.conf' % NOVA_CONF_DIR
_resource_map[NOVA_CONF]['contexts'].append(
ch_context.KeystoneAuditMiddleware(service='nova'))
_resource_map[NOVA_API_PASTE]['contexts'].append(
ch_context.KeystoneAuditMiddleware(service='nova'))
_BASE_RESOURCE_MAP[NOVA_AUDIT_MAP] = {
'contexts': [ch_context.KeystoneAuditMiddleware(service='nova')],
'services': AUDIT_SERVICES,
}

if common.console_attributes('services'):
_resource_map[NOVA_CONF]['services'] += (
common.console_attributes('services'))
Expand Down
137 changes: 137 additions & 0 deletions templates/yoga/api-paste.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
############
# Metadata #
############
[composite:metadata]
use = egg:Paste#urlmap
/: meta

[pipeline:meta]
pipeline = cors metaapp

[app:metaapp]
paste.app_factory = nova.api.metadata.handler:MetadataRequestHandler.factory

#############
# OpenStack #
#############

[composite:osapi_compute]
use = call:nova.api.openstack.urlmap:urlmap_factory
/: oscomputeversions
# starting in Liberty the v21 implementation replaces the v2
# implementation and is suggested that you use it as the default. If
# this causes issues with your clients you can rollback to the
# *frozen* v2 api by commenting out the above stanza and using the
# following instead::
# /v2: openstack_compute_api_legacy_v2
# if rolling back to v2 fixes your issue please file a critical bug
# at - https://bugs.launchpad.net/nova/+bugs
#
# v21 is an exactly feature match for v2, except it has more stringent
# input validation on the wsgi surface (prevents fuzzing early on the
# API). It also provides new features via API microversions which are
# opt into for clients. Unaware clients will receive the same frozen
# v2 API feature set, but with some relaxed validation
/v2: openstack_compute_api_v21_legacy_v2_compatible
/v2.1: openstack_compute_api_v21

# NOTE: this is deprecated in favor of openstack_compute_api_v21_legacy_v2_compatible
[composite:openstack_compute_api_legacy_v2]
use = call:nova.api.auth:pipeline_factory
noauth2 = cors compute_req_id faultwrap sizelimit noauth2 legacy_ratelimit osapi_compute_app_legacy_v2
{% if audit_middleware and service_name -%}
keystone = cors compute_req_id faultwrap sizelimit authtoken keystonecontext legacy_ratelimit audit osapi_compute_app_legacy_v2
keystone_nolimit = cors compute_req_id faultwrap sizelimit authtoken keystonecontext audit osapi_compute_app_legacy_v2
{% else -%}
keystone = cors compute_req_id faultwrap sizelimit authtoken keystonecontext legacy_ratelimit osapi_compute_app_legacy_v2
keystone_nolimit = cors compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_legacy_v2
{% endif %}

[composite:openstack_compute_api_v21]
use = call:nova.api.auth:pipeline_factory_v21
noauth2 = cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit noauth2 osapi_compute_app_v21
{% if audit_middleware and service_name -%}
keystone = cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit authtoken keystonecontext audit osapi_compute_app_v21
{% else -%}
keystone = cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v21
{% endif %}

[composite:openstack_compute_api_v21_legacy_v2_compatible]
use = call:nova.api.auth:pipeline_factory_v21
noauth2 = cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit noauth2 legacy_v2_compatible osapi_compute_app_v21
{% if audit_middleware and service_name -%}
keystone = cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit authtoken keystonecontext legacy_v2_compatible audit osapi_compute_app_v21
{% else -%}
keystone = cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit authtoken keystonecontext legacy_v2_compatible osapi_compute_app_v21
{% endif %}

[filter:request_id]
paste.filter_factory = oslo_middleware:RequestId.factory

[filter:compute_req_id]
paste.filter_factory = nova.api.compute_req_id:ComputeReqIdMiddleware.factory

[filter:faultwrap]
paste.filter_factory = nova.api.openstack:FaultWrapper.factory

[filter:noauth2]
paste.filter_factory = nova.api.openstack.auth:NoAuthMiddleware.factory

[filter:legacy_ratelimit]
paste.filter_factory = nova.api.openstack.compute.limits:RateLimitingMiddleware.factory
{% if api_rate_limit_rules -%}
limits = {{ api_rate_limit_rules }}
{% endif -%}

[filter:sizelimit]
paste.filter_factory = oslo_middleware:RequestBodySizeLimiter.factory

[filter:http_proxy_to_wsgi]
paste.filter_factory = oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory

[filter:legacy_v2_compatible]
paste.filter_factory = nova.api.openstack:LegacyV2CompatibleWrapper.factory

[app:osapi_compute_app_legacy_v2]
paste.app_factory = nova.api.openstack.compute:APIRouter.factory

[app:osapi_compute_app_v21]
paste.app_factory = nova.api.openstack.compute:APIRouterV21.factory

[pipeline:oscomputeversions]
pipeline = faultwrap http_proxy_to_wsgi oscomputeversionapp

[app:oscomputeversionapp]
paste.app_factory = nova.api.openstack.compute.versions:Versions.factory

##########
# Shared #
##########

[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
oslo_config_project = nova

[filter:keystonecontext]
paste.filter_factory = nova.api.auth:NovaKeystoneContext.factory

[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory

{% include "section-filter-audit" %}

{% if service_host -%}
# NOTE(jamespage) - not used - but required for relation to nova-compute
service_protocol = {{ service_protocol }}
service_host = {{ service_host }}
service_port = {{ service_port }}
auth_host = {{ auth_host }}
auth_port = {{ auth_port }}
auth_protocol = {{ auth_protocol }}
admin_tenant_name = {{ admin_tenant_name }}
admin_user = {{ admin_user }}
admin_password = {{ admin_password }}
{% if admin_domain_name -%}
admin_domain_name = {{ admin_domain_name }}
{% endif -%}
{% endif -%}
72 changes: 72 additions & 0 deletions templates/yoga/api_audit_map.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
[DEFAULT]
# default target endpoint type
# should match the endpoint type defined in service catalog
target_endpoint_type = None

[custom_actions]
enable = enable
disable = disable
delete = delete
startup = start/startup
shutdown = stop/shutdown
reboot = start/reboot
os-migrations/get = read
os-server-password/post = update

# possible end path of api requests
[path_keywords]
add = None
action = None
enable = None
disable = None
configure-project = None
defaults = None
delete = None
detail = None
diagnostics = None
entries = entry
extensions = alias
flavors = flavor
images = image
ips = label
limits = None
metadata = key
os-agents = os-agent
os-aggregates = os-aggregate
os-availability-zone = None
os-certificates = None
os-cloudpipe = None
os-fixed-ips = ip
os-extra_specs = key
os-flavor-access = None
os-floating-ip-dns = domain
os-floating-ips-bulk = host
os-floating-ip-pools = None
os-floating-ips = floating-ip
os-hosts = host
os-hypervisors = hypervisor
os-instance-actions = instance-action
os-keypairs = keypair
os-migrations = None
os-networks = network
os-quota-sets = tenant
os-security-groups = security_group
os-security-group-rules = rule
os-server-password = None
os-services = None
os-simple-tenant-usage = tenant
os-virtual-interfaces = None
os-volume_attachments = attachment
os-volumes_boot = None
os-volumes = volume
os-volume-types = volume-type
os-snapshots = snapshot
reboot = None
servers = server
shutdown = None
startup = None
statistics = None

# map endpoint type defined in service catalog to CADF typeURI
[service_endpoints]
compute = service/compute
Loading

0 comments on commit cd97750

Please sign in to comment.