Add keystone audit middleware API logging
This commit adds Keystone audit middleware API logging to the Heat
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/heat/heat-api.log.
This commit builds on previous discussions:
https://github.com/juju/charm-helpers/pull/808.
func-test-pr: https://github.com/openstack-charmers/zaza-openstack-tests/pull/1212
Closes-Bug: 1856555
Change-Id: Ic611b68f35a36489673e3430dd1abbd5aa752fa7
(cherry picked from commit 69886c1bcd
)
This commit is contained in:
parent
52d0a06868
commit
5f61266f26
@ -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: bobcat
|
||||
|
@ -120,6 +120,7 @@ SVC = 'heat'
|
||||
HEAT_DIR = '/etc/heat'
|
||||
HEAT_CONF = '/etc/heat/heat.conf'
|
||||
HEAT_API_PASTE = '/etc/heat/api-paste.ini'
|
||||
HEAT_AUDIT_CONF = '%s/api_audit_map.conf' % HEAT_DIR
|
||||
HAPROXY_CONF = '/etc/haproxy/haproxy.cfg'
|
||||
APACHE_PORTS_CONF = '/etc/apache2/ports.conf'
|
||||
HTTPS_APACHE_CONF = '/etc/apache2/sites-available/openstack_https_frontend'
|
||||
@ -147,17 +148,23 @@ CONFIG_FILES = OrderedDict([
|
||||
context.WorkerConfigContext(),
|
||||
context.BindHostContext(),
|
||||
context.MemcacheContext(),
|
||||
context.OSConfigFlagContext()],
|
||||
context.OSConfigFlagContext(),
|
||||
context.KeystoneAuditMiddleware(service=SVC)]
|
||||
}),
|
||||
(HEAT_API_PASTE, {
|
||||
'services': [s for s in BASE_SERVICES if 'api' in s],
|
||||
'contexts': [HeatIdentityServiceContext()],
|
||||
'contexts': [HeatIdentityServiceContext(),
|
||||
context.KeystoneAuditMiddleware(service=SVC)],
|
||||
}),
|
||||
(HAPROXY_CONF, {
|
||||
'contexts': [context.HAProxyContext(singlenode_mode=True),
|
||||
HeatHAProxyContext()],
|
||||
'services': ['haproxy'],
|
||||
}),
|
||||
(HEAT_AUDIT_CONF, {
|
||||
'contexts': [context.KeystoneAuditMiddleware(service=SVC)],
|
||||
'services': ['heat-api']
|
||||
}),
|
||||
(HTTPS_APACHE_CONF, {
|
||||
'contexts': [HeatApacheSSLContext()],
|
||||
'services': ['apache2'],
|
||||
|
130
templates/yoga/api-paste.ini
Normal file
130
templates/yoga/api-paste.ini
Normal file
@ -0,0 +1,130 @@
|
||||
# yoga
|
||||
# heat-api pipeline
|
||||
[pipeline:heat-api]
|
||||
{% if audit_middleware and service_name %}
|
||||
pipeline = healthcheck cors request_id faultwrap http_proxy_to_wsgi versionnegotiation osprofiler authurl authtoken audit context apiv1app
|
||||
{% else %}
|
||||
pipeline = healthcheck cors request_id faultwrap http_proxy_to_wsgi versionnegotiation osprofiler authurl authtoken context apiv1app
|
||||
{% endif %}
|
||||
|
||||
|
||||
# heat-api pipeline for standalone heat
|
||||
# ie. uses alternative auth backend that authenticates users against keystone
|
||||
# using username and password instead of validating token (which requires
|
||||
# an admin/service token).
|
||||
# To enable, in heat.conf:
|
||||
# [paste_deploy]
|
||||
# flavor = standalone
|
||||
#
|
||||
[pipeline:heat-api-standalone]
|
||||
{% if audit_middleware and service_name %}
|
||||
pipeline = healthcheck cors request_id faultwrap http_proxy_to_wsgi versionnegotiation authurl authpassword audit context apiv1app
|
||||
{% else %}
|
||||
pipeline = healthcheck cors request_id faultwrap http_proxy_to_wsgi versionnegotiation authurl authpassword context apiv1app
|
||||
{% endif %}
|
||||
|
||||
# heat-api pipeline for custom cloud backends
|
||||
# i.e. in heat.conf:
|
||||
# [paste_deploy]
|
||||
# flavor = custombackend
|
||||
#
|
||||
[pipeline:heat-api-custombackend]
|
||||
pipeline = healthcheck cors request_id faultwrap versionnegotiation context custombackendauth apiv1app
|
||||
|
||||
# To enable, in heat.conf:
|
||||
# [paste_deploy]
|
||||
# flavor = noauth
|
||||
#
|
||||
[pipeline:heat-api-noauth]
|
||||
pipeline = healthcheck cors request_id faultwrap http_proxy_to_wsgi versionnegotiation noauth context apiv1app
|
||||
|
||||
# heat-api-cfn pipeline
|
||||
[pipeline:heat-api-cfn]
|
||||
pipeline = healthcheck cors http_proxy_to_wsgi cfnversionnegotiation osprofiler ec2authtoken authtoken context apicfnv1app
|
||||
|
||||
# heat-api-cfn pipeline for standalone heat
|
||||
# relies exclusively on authenticating with ec2 signed requests
|
||||
[pipeline:heat-api-cfn-standalone]
|
||||
pipeline = healthcheck cors http_proxy_to_wsgi cfnversionnegotiation ec2authtoken context apicfnv1app
|
||||
|
||||
# heat-api-cloudwatch pipeline
|
||||
[pipeline:heat-api-cloudwatch]
|
||||
pipeline = healthcheck cors versionnegotiation osprofiler ec2authtoken authtoken context apicwapp
|
||||
|
||||
# heat-api-cloudwatch pipeline for standalone heat
|
||||
# relies exclusively on authenticating with ec2 signed requests
|
||||
[pipeline:heat-api-cloudwatch-standalone]
|
||||
pipeline = healthcheck cors versionnegotiation ec2authtoken context apicwapp
|
||||
|
||||
[app:apiv1app]
|
||||
paste.app_factory = heat.common.wsgi:app_factory
|
||||
heat.app_factory = heat.api.openstack.v1:API
|
||||
|
||||
[app:apicfnv1app]
|
||||
paste.app_factory = heat.common.wsgi:app_factory
|
||||
heat.app_factory = heat.api.cfn.v1:API
|
||||
|
||||
[app:apicwapp]
|
||||
paste.app_factory = heat.common.wsgi:app_factory
|
||||
heat.app_factory = heat.api.cloudwatch:API
|
||||
|
||||
[filter:versionnegotiation]
|
||||
paste.filter_factory = heat.common.wsgi:filter_factory
|
||||
heat.filter_factory = heat.api.openstack:version_negotiation_filter
|
||||
|
||||
[filter:cors]
|
||||
paste.filter_factory = oslo_middleware.cors:filter_factory
|
||||
oslo_config_project = heat
|
||||
|
||||
[filter:faultwrap]
|
||||
paste.filter_factory = heat.common.wsgi:filter_factory
|
||||
heat.filter_factory = heat.api.openstack:faultwrap_filter
|
||||
|
||||
[filter:cfnversionnegotiation]
|
||||
paste.filter_factory = heat.common.wsgi:filter_factory
|
||||
heat.filter_factory = heat.api.cfn:version_negotiation_filter
|
||||
|
||||
[filter:cwversionnegotiation]
|
||||
paste.filter_factory = heat.common.wsgi:filter_factory
|
||||
heat.filter_factory = heat.api.cloudwatch:version_negotiation_filter
|
||||
|
||||
[filter:context]
|
||||
paste.filter_factory = heat.common.context:ContextMiddleware_filter_factory
|
||||
|
||||
[filter:ec2authtoken]
|
||||
paste.filter_factory = heat.api.aws.ec2token:EC2Token_filter_factory
|
||||
|
||||
[filter:http_proxy_to_wsgi]
|
||||
paste.filter_factory = oslo_middleware:HTTPProxyToWSGI.factory
|
||||
|
||||
# Middleware to set auth_url header appropriately
|
||||
[filter:authurl]
|
||||
paste.filter_factory = heat.common.auth_url:filter_factory
|
||||
|
||||
# Auth middleware that validates token against keystone
|
||||
[filter:authtoken]
|
||||
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
|
||||
|
||||
# Auth middleware that validates username/password against keystone
|
||||
[filter:authpassword]
|
||||
paste.filter_factory = heat.common.auth_password:filter_factory
|
||||
|
||||
# Auth middleware that validates against custom backend
|
||||
[filter:custombackendauth]
|
||||
paste.filter_factory = heat.common.custom_backend_auth:filter_factory
|
||||
|
||||
# Auth middleware that accepts any auth
|
||||
[filter:noauth]
|
||||
paste.filter_factory = heat.common.noauth:filter_factory
|
||||
|
||||
# Middleware to set x-openstack-request-id in http response header
|
||||
[filter:request_id]
|
||||
paste.filter_factory = oslo_middleware.request_id:RequestId.factory
|
||||
|
||||
[filter:osprofiler]
|
||||
paste.filter_factory = osprofiler.web:WsgiMiddleware.factory
|
||||
|
||||
[filter:healthcheck]
|
||||
paste.filter_factory = oslo_middleware:Healthcheck.factory
|
||||
|
||||
{% include "section-filter-audit" %}
|
32
templates/yoga/api_audit_map.conf
Normal file
32
templates/yoga/api_audit_map.conf
Normal file
@ -0,0 +1,32 @@
|
||||
[DEFAULT]
|
||||
# default target endpoint type
|
||||
# should match the endpoint type defined in service catalog
|
||||
target_endpoint_type = None
|
||||
|
||||
# possible end path of api requests
|
||||
[path_keywords]
|
||||
stacks = stack
|
||||
resources = resource
|
||||
preview = None
|
||||
detail = None
|
||||
abandon = None
|
||||
snapshots = snapshot
|
||||
restore = None
|
||||
outputs = output
|
||||
metadata = server
|
||||
signal = None
|
||||
events = event
|
||||
template = None
|
||||
template_versions = template_version
|
||||
functions = None
|
||||
validate = None
|
||||
resource_types = resource_type
|
||||
build_info = None
|
||||
actions = None
|
||||
software_configs = software_config
|
||||
software_deployments = software_deployment
|
||||
services = None
|
||||
|
||||
# map endpoint type defined in service catalog to CADF typeURI
|
||||
[service_endpoints]
|
||||
orchestration = service/orchestration
|
107
templates/yoga/heat.conf
Normal file
107
templates/yoga/heat.conf
Normal file
@ -0,0 +1,107 @@
|
||||
[DEFAULT]
|
||||
use_syslog = {{ use_syslog }}
|
||||
debug = {{ debug }}
|
||||
verbose = {{ verbose }}
|
||||
log_dir = /var/log/heat
|
||||
instance_user = {{ instance_user }}
|
||||
instance_driver = heat.engine.nova
|
||||
{% if plugin_dirs -%}
|
||||
plugin_dirs = {{ plugin_dirs }}
|
||||
{% else -%}
|
||||
plugin_dirs = /usr/lib64/heat,/usr/lib/heat
|
||||
{% endif -%}
|
||||
environment_dir = /etc/heat/environment.d
|
||||
host = heat
|
||||
auth_encryption_key = {{ encryption_key }}
|
||||
deferred_auth_method = trusts
|
||||
stack_domain_admin = heat_domain_admin
|
||||
stack_domain_admin_password = {{ heat_domain_admin_passwd }}
|
||||
stack_user_domain_name = heat
|
||||
num_engine_workers = {{ workers }}
|
||||
{%- if max_stacks_per_tenant %}
|
||||
max_stacks_per_tenant = {{ max_stacks_per_tenant }}
|
||||
{%- endif %}
|
||||
{% if sections and 'DEFAULT' in sections -%}
|
||||
{% for key, value in sections['DEFAULT'] -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
{% if user_config_flags -%}
|
||||
{% for key, value in user_config_flags.items() -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if transport_url %}
|
||||
transport_url = {{ transport_url }}
|
||||
{% endif %}
|
||||
|
||||
{% if auth_host -%}
|
||||
{% include "section-keystone-authtoken-mitaka" %}
|
||||
|
||||
[trustee]
|
||||
auth_plugin = password
|
||||
auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
|
||||
username = {{ admin_user }}
|
||||
password = {{ admin_password }}
|
||||
user_domain_name = default
|
||||
|
||||
[clients_keystone]
|
||||
auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}
|
||||
|
||||
[ec2_authtoken]
|
||||
auth_uri = {{service_protocol }}://{{ service_host }}:{{ service_port }}
|
||||
keystone_ec2_uri = {{service_protocol }}://{{ service_host }}:{{ service_port }}/v2.0/ec2tokens
|
||||
{% endif %}
|
||||
|
||||
{% if database_host -%}
|
||||
[database]
|
||||
connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
[paste_deploy]
|
||||
api_paste_config=/etc/heat/api-paste.ini
|
||||
|
||||
[heat_api]
|
||||
bind_host = {{ bind_host }}
|
||||
{% if api_listen_port -%}
|
||||
bind_port={{ api_listen_port }}
|
||||
{% else -%}
|
||||
bind_port=8004
|
||||
{% endif %}
|
||||
workers = {{ workers }}
|
||||
|
||||
[heat_api_cfn]
|
||||
bind_host = {{ bind_host }}
|
||||
{% if api_cfn_listen_port -%}
|
||||
bind_port={{ api_cfn_listen_port }}
|
||||
{% else -%}
|
||||
bind_port=8000
|
||||
{% endif %}
|
||||
workers = {{ workers }}
|
||||
|
||||
{% include "section-oslo-messaging-rabbit-ocata" %}
|
||||
|
||||
{% if use_internal_endpoints -%}
|
||||
[clients]
|
||||
endpoint_type = internalURL
|
||||
|
||||
[clients_heat]
|
||||
# See LP 1770144
|
||||
endpoint_type = publicURL
|
||||
|
||||
{%- endif %}
|
||||
|
||||
{% include "section-oslo-middleware" %}
|
||||
|
||||
{% if sections -%}
|
||||
{% for section in sections if section != 'DEFAULT' -%}
|
||||
[{{ section }}]
|
||||
{% for key, value in sections[section] -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
{% include "section-audit-middleware-notifications" %}
|
@ -16,9 +16,13 @@ configure:
|
||||
tests:
|
||||
- zaza.openstack.charm_tests.heat.tests.HeatBasicDeployment
|
||||
- zaza.openstack.charm_tests.policyd.tests.HeatTests
|
||||
- zaza.openstack.charm_tests.audit.tests.KeystoneAuditMiddlewareTest
|
||||
|
||||
tests_options:
|
||||
policyd:
|
||||
service: heat
|
||||
audit-middleware:
|
||||
service: heat
|
||||
|
||||
force_deploy:
|
||||
- noble-caracal
|
||||
|
@ -50,6 +50,7 @@ RESTART_MAP = OrderedDict([
|
||||
('/etc/heat/heat.conf', ['heat-api', 'heat-api-cfn', 'heat-engine']),
|
||||
('/etc/heat/api-paste.ini', ['heat-api', 'heat-api-cfn']),
|
||||
('/etc/haproxy/haproxy.cfg', ['haproxy']),
|
||||
('/etc/heat/api_audit_map.conf', ['heat-api']),
|
||||
('/etc/apache2/sites-available/openstack_https_frontend', ['apache2']),
|
||||
('/etc/apache2/sites-available/openstack_https_frontend.conf',
|
||||
['apache2']),
|
||||
|
Loading…
Reference in New Issue
Block a user