mirror of
https://github.com/ansible/awx.git
synced 2026-01-10 15:32:07 -03:30
cherry-pick 222f387 to release_4.6 (#6971)
This commit is contained in:
parent
4eefce622d
commit
f4347d05a9
@ -50,9 +50,6 @@ from ansible_base.lib.utils.models import get_type_for_model
|
||||
from ansible_base.rbac.models import RoleEvaluation, ObjectRole
|
||||
from ansible_base.rbac import permission_registry
|
||||
|
||||
# django-flags
|
||||
from flags.state import flag_enabled
|
||||
|
||||
# AWX
|
||||
from awx.main.access import get_user_capabilities
|
||||
from awx.main.constants import ACTIVE_STATES, CENSOR_VALUE, org_role_to_permission
|
||||
@ -745,13 +742,10 @@ class EmptySerializer(serializers.Serializer):
|
||||
pass
|
||||
|
||||
|
||||
class OpaQueryPathEnabledMixin(serializers.Serializer):
|
||||
class OpaQueryPathMixin(serializers.Serializer):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if not flag_enabled("FEATURE_POLICY_AS_CODE_ENABLED") and 'opa_query_path' in self.fields:
|
||||
self.fields.pop('opa_query_path')
|
||||
|
||||
def validate_opa_query_path(self, value):
|
||||
# Decode the URL and re-encode it
|
||||
decoded_value = urllib.parse.unquote(value)
|
||||
@ -763,7 +757,7 @@ class OpaQueryPathEnabledMixin(serializers.Serializer):
|
||||
return value
|
||||
|
||||
|
||||
class UnifiedJobTemplateSerializer(BaseSerializer, OpaQueryPathEnabledMixin):
|
||||
class UnifiedJobTemplateSerializer(BaseSerializer, OpaQueryPathMixin):
|
||||
# As a base serializer, the capabilities prefetch is not used directly,
|
||||
# instead they are derived from the Workflow Job Template Serializer and the Job Template Serializer, respectively.
|
||||
capabilities_prefetch = []
|
||||
@ -1440,7 +1434,7 @@ class OAuth2ApplicationSerializer(BaseSerializer):
|
||||
return ret
|
||||
|
||||
|
||||
class OrganizationSerializer(BaseSerializer, OpaQueryPathEnabledMixin):
|
||||
class OrganizationSerializer(BaseSerializer, OpaQueryPathMixin):
|
||||
show_capabilities = ['edit', 'delete']
|
||||
|
||||
class Meta:
|
||||
@ -1800,7 +1794,7 @@ class LabelsListMixin(object):
|
||||
return res
|
||||
|
||||
|
||||
class InventorySerializer(LabelsListMixin, BaseSerializerWithVariables, OpaQueryPathEnabledMixin):
|
||||
class InventorySerializer(LabelsListMixin, BaseSerializerWithVariables, OpaQueryPathMixin):
|
||||
show_capabilities = ['edit', 'delete', 'adhoc', 'copy']
|
||||
capabilities_prefetch = ['admin', 'adhoc', {'copy': 'organization.inventory_admin'}]
|
||||
|
||||
|
||||
234
awx/main/conf.py
234
awx/main/conf.py
@ -4,7 +4,6 @@ import logging
|
||||
# Django
|
||||
from django.core.checks import Error
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
# Django REST Framework
|
||||
from rest_framework import serializers
|
||||
@ -997,131 +996,132 @@ def csrf_trusted_origins_validate(serializer, attrs):
|
||||
register_validate('system', csrf_trusted_origins_validate)
|
||||
|
||||
|
||||
if settings.FEATURE_POLICY_AS_CODE_ENABLED: # Unable to use flag_enabled due to AppRegistryNotReady error
|
||||
register(
|
||||
'OPA_HOST',
|
||||
field_class=fields.CharField,
|
||||
label=_('OPA server hostname'),
|
||||
default='',
|
||||
help_text=_('The hostname used to connect to the OPA server. If empty, policy enforcement will be disabled.'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
allow_blank=True,
|
||||
)
|
||||
register(
|
||||
'OPA_HOST',
|
||||
field_class=fields.CharField,
|
||||
label=_('OPA server hostname'),
|
||||
default='',
|
||||
help_text=_('The hostname used to connect to the OPA server. If empty, policy enforcement will be disabled.'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
allow_blank=True,
|
||||
)
|
||||
|
||||
register(
|
||||
'OPA_PORT',
|
||||
field_class=fields.IntegerField,
|
||||
label=_('OPA server port'),
|
||||
default=8181,
|
||||
help_text=_('The port used to connect to the OPA server. Defaults to 8181.'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
register(
|
||||
'OPA_PORT',
|
||||
field_class=fields.IntegerField,
|
||||
label=_('OPA server port'),
|
||||
default=8181,
|
||||
help_text=_('The port used to connect to the OPA server. Defaults to 8181.'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
|
||||
register(
|
||||
'OPA_SSL',
|
||||
field_class=fields.BooleanField,
|
||||
label=_('Use SSL for OPA connection'),
|
||||
default=False,
|
||||
help_text=_('Enable or disable the use of SSL to connect to the OPA server. Defaults to false.'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
register(
|
||||
'OPA_SSL',
|
||||
field_class=fields.BooleanField,
|
||||
label=_('Use SSL for OPA connection'),
|
||||
default=False,
|
||||
help_text=_('Enable or disable the use of SSL to connect to the OPA server. Defaults to false.'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
|
||||
register(
|
||||
'OPA_AUTH_TYPE',
|
||||
field_class=fields.ChoiceField,
|
||||
label=_('OPA authentication type'),
|
||||
choices=[OPA_AUTH_TYPES.NONE, OPA_AUTH_TYPES.TOKEN, OPA_AUTH_TYPES.CERTIFICATE],
|
||||
default=OPA_AUTH_TYPES.NONE,
|
||||
help_text=_('The authentication type that will be used to connect to the OPA server: "None", "Token", or "Certificate".'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
register(
|
||||
'OPA_AUTH_TYPE',
|
||||
field_class=fields.ChoiceField,
|
||||
label=_('OPA authentication type'),
|
||||
choices=[OPA_AUTH_TYPES.NONE, OPA_AUTH_TYPES.TOKEN, OPA_AUTH_TYPES.CERTIFICATE],
|
||||
default=OPA_AUTH_TYPES.NONE,
|
||||
help_text=_('The authentication type that will be used to connect to the OPA server: "None", "Token", or "Certificate".'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
|
||||
register(
|
||||
'OPA_AUTH_TOKEN',
|
||||
field_class=fields.CharField,
|
||||
label=_('OPA authentication token'),
|
||||
default='',
|
||||
help_text=_(
|
||||
'The token for authentication to the OPA server. Required when OPA_AUTH_TYPE is "Token". If an authorization header is defined in OPA_AUTH_CUSTOM_HEADERS, it will be overridden by OPA_AUTH_TOKEN.'
|
||||
),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
allow_blank=True,
|
||||
encrypted=True,
|
||||
)
|
||||
register(
|
||||
'OPA_AUTH_TOKEN',
|
||||
field_class=fields.CharField,
|
||||
label=_('OPA authentication token'),
|
||||
default='',
|
||||
help_text=_(
|
||||
'The token for authentication to the OPA server. Required when OPA_AUTH_TYPE is "Token". If an authorization header is defined in OPA_AUTH_CUSTOM_HEADERS, it will be overridden by OPA_AUTH_TOKEN.'
|
||||
),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
allow_blank=True,
|
||||
encrypted=True,
|
||||
)
|
||||
|
||||
register(
|
||||
'OPA_AUTH_CLIENT_CERT',
|
||||
field_class=fields.CharField,
|
||||
label=_('OPA client certificate content'),
|
||||
default='',
|
||||
help_text=_('The content of the client certificate file for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate".'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
allow_blank=True,
|
||||
)
|
||||
register(
|
||||
'OPA_AUTH_CLIENT_CERT',
|
||||
field_class=fields.CharField,
|
||||
label=_('OPA client certificate content'),
|
||||
default='',
|
||||
help_text=_('The content of the client certificate file for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate".'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
allow_blank=True,
|
||||
)
|
||||
|
||||
register(
|
||||
'OPA_AUTH_CLIENT_KEY',
|
||||
field_class=fields.CharField,
|
||||
label=_('OPA client key content'),
|
||||
default='',
|
||||
help_text=_('The content of the client key for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate".'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
allow_blank=True,
|
||||
encrypted=True,
|
||||
)
|
||||
register(
|
||||
'OPA_AUTH_CLIENT_KEY',
|
||||
field_class=fields.CharField,
|
||||
label=_('OPA client key content'),
|
||||
default='',
|
||||
help_text=_('The content of the client key for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate".'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
allow_blank=True,
|
||||
encrypted=True,
|
||||
)
|
||||
|
||||
register(
|
||||
'OPA_AUTH_CA_CERT',
|
||||
field_class=fields.CharField,
|
||||
label=_('OPA CA certificate content'),
|
||||
default='',
|
||||
help_text=_('The content of the CA certificate for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate".'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
allow_blank=True,
|
||||
)
|
||||
register(
|
||||
'OPA_AUTH_CA_CERT',
|
||||
field_class=fields.CharField,
|
||||
label=_('OPA CA certificate content'),
|
||||
default='',
|
||||
help_text=_('The content of the CA certificate for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate".'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
allow_blank=True,
|
||||
)
|
||||
|
||||
register(
|
||||
'OPA_AUTH_CUSTOM_HEADERS',
|
||||
field_class=fields.DictField,
|
||||
label=_('OPA custom authentication headers'),
|
||||
default={},
|
||||
help_text=_('Optional custom headers included in requests to the OPA server. Defaults to empty dictionary ({}).'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
register(
|
||||
'OPA_AUTH_CUSTOM_HEADERS',
|
||||
field_class=fields.DictField,
|
||||
label=_('OPA custom authentication headers'),
|
||||
default={},
|
||||
help_text=_('Optional custom headers included in requests to the OPA server. Defaults to empty dictionary ({}).'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
|
||||
register(
|
||||
'OPA_REQUEST_TIMEOUT',
|
||||
field_class=fields.FloatField,
|
||||
label=_('OPA request timeout'),
|
||||
default=1.5,
|
||||
help_text=_('The number of seconds after which the connection to the OPA server will time out. Defaults to 1.5 seconds.'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
register(
|
||||
'OPA_REQUEST_TIMEOUT',
|
||||
field_class=fields.FloatField,
|
||||
label=_('OPA request timeout'),
|
||||
default=1.5,
|
||||
help_text=_('The number of seconds after which the connection to the OPA server will time out. Defaults to 1.5 seconds.'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
|
||||
register(
|
||||
'OPA_REQUEST_RETRIES',
|
||||
field_class=fields.IntegerField,
|
||||
label=_('OPA request retry count'),
|
||||
default=2,
|
||||
help_text=_('The number of retry attempts for connecting to the OPA server. Default is 2.'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
register(
|
||||
'OPA_REQUEST_RETRIES',
|
||||
field_class=fields.IntegerField,
|
||||
label=_('OPA request retry count'),
|
||||
default=2,
|
||||
help_text=_('The number of retry attempts for connecting to the OPA server. Default is 2.'),
|
||||
category=('PolicyAsCode'),
|
||||
category_slug='policyascode',
|
||||
)
|
||||
|
||||
def policy_as_code_validate(serializer, attrs):
|
||||
opa_host = attrs.get('OPA_HOST', '')
|
||||
if opa_host and (opa_host.startswith('http://') or opa_host.startswith('https://')):
|
||||
raise serializers.ValidationError({'OPA_HOST': _("OPA_HOST should not include 'http://' or 'https://' prefixes. Please enter only the hostname.")})
|
||||
return attrs
|
||||
|
||||
register_validate('policyascode', policy_as_code_validate)
|
||||
def policy_as_code_validate(serializer, attrs):
|
||||
opa_host = attrs.get('OPA_HOST', '')
|
||||
if opa_host and (opa_host.startswith('http://') or opa_host.startswith('https://')):
|
||||
raise serializers.ValidationError({'OPA_HOST': _("OPA_HOST should not include 'http://' or 'https://' prefixes. Please enter only the hostname.")})
|
||||
return attrs
|
||||
|
||||
|
||||
register_validate('policyascode', policy_as_code_validate)
|
||||
|
||||
@ -8,7 +8,6 @@ from typing import Optional, Union
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from flags.state import flag_enabled
|
||||
from opa_client import OpaClient
|
||||
from opa_client.base import BaseClient
|
||||
from requests import HTTPError
|
||||
@ -364,9 +363,6 @@ def opa_client(headers=None):
|
||||
|
||||
def evaluate_policy(instance):
|
||||
# Policy evaluation for Policy as Code feature
|
||||
if not flag_enabled("FEATURE_POLICY_AS_CODE_ENABLED"):
|
||||
return
|
||||
|
||||
if not settings.OPA_HOST:
|
||||
return
|
||||
|
||||
|
||||
@ -36,11 +36,9 @@ def _parse_exception_message(exception: PolicyEvaluationError):
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def enable_flag():
|
||||
def setup_opa_settings():
|
||||
with override_settings(
|
||||
OPA_HOST='opa.example.com',
|
||||
FLAGS={"FEATURE_POLICY_AS_CODE_ENABLED": [("boolean", True)]},
|
||||
FLAG_SOURCES=('flags.sources.SettingsFlagsSource',),
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
@ -1255,8 +1255,8 @@ OPA_REQUEST_RETRIES = 2 # The number of retry attempts for connecting to the OP
|
||||
# feature flags
|
||||
FLAG_SOURCES = ('flags.sources.SettingsFlagsSource',)
|
||||
FLAGS = {
|
||||
'FEATURE_POLICY_AS_CODE_ENABLED': [{'condition': 'boolean', 'value': False}],
|
||||
'FEATURE_INDIRECT_NODE_COUNTING_ENABLED': [{'condition': 'boolean', 'value': False}],
|
||||
'FEATURE_DISPATCHERD_ENABLED': [{'condition': 'boolean', 'value': False}],
|
||||
}
|
||||
|
||||
# Dispatcher worker lifetime. If set to None, workers will never be retired
|
||||
|
||||
@ -93,6 +93,9 @@ needs_development = ['inventory_script', 'instance']
|
||||
needs_param_development = {
|
||||
'host': ['instance_id'],
|
||||
'workflow_approval': ['description', 'execution_environment'],
|
||||
'inventory': ['opa_query_path'],
|
||||
'job_template': ['opa_query_path'],
|
||||
'organization': ['opa_query_path'],
|
||||
}
|
||||
# -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user