-
Notifications
You must be signed in to change notification settings - Fork 372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Block extensions disallowed by policy #3259
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,7 @@ | |
from azurelinuxagent.common.agent_supported_feature import get_agent_supported_features_list_for_extensions, \ | ||
SupportedFeatureNames, get_supported_feature_by_name, get_agent_supported_features_list_for_crp | ||
from azurelinuxagent.ga.cgroupconfigurator import CGroupConfigurator | ||
from azurelinuxagent.ga.policy.policy_engine import ExtensionPolicyEngine, ExtensionPolicyError | ||
from azurelinuxagent.common.datacontract import get_properties, set_properties | ||
from azurelinuxagent.common.errorstate import ErrorState | ||
from azurelinuxagent.common.event import add_event, elapsed_milliseconds, WALAEventOperation, \ | ||
|
@@ -482,10 +483,49 @@ def handle_ext_handlers(self, goal_state_id): | |
depends_on_err_msg = None | ||
extensions_enabled = conf.get_extensions_enabled() | ||
|
||
# Instantiate policy engine, and use same engine to handle all extension handlers. | ||
# If an error is thrown during policy engine initialization, we block all extensions and report the error via handler/extension status for | ||
# each extension. | ||
policy_error = None | ||
try: | ||
policy_engine = ExtensionPolicyEngine() | ||
except Exception as ex: | ||
policy_error = ex | ||
|
||
for extension, ext_handler in all_extensions: | ||
|
||
handler_i = ExtHandlerInstance(ext_handler, self.protocol, extension=extension) | ||
|
||
# Invoke policy engine to determine if extension is allowed. If not, block extension and report error on | ||
# behalf of the extension. | ||
policy_err_map = { | ||
ExtensionRequestedState.Enabled: ('enable', ExtensionErrorCodes.PluginEnableProcessingFailed), | ||
# TODO: CRP does not currently have a terminal error code for uninstall. Once CRP adds | ||
# an error code for uninstall or for policy, use this code instead of PluginDisableProcessingFailed | ||
# Note that currently, CRP waits for 90 minutes to time out for a failed uninstall operation, instead of | ||
# failing fast. | ||
ExtensionRequestedState.Uninstall: ('uninstall', ExtensionErrorCodes.PluginDisableProcessingFailed), | ||
ExtensionRequestedState.Disabled: ('disable', ExtensionErrorCodes.PluginDisableProcessingFailed), | ||
} | ||
policy_op, policy_err_code = policy_err_map.get(ext_handler.state) | ||
if policy_error is not None: | ||
err = ExtensionPolicyError(msg="", inner=policy_error, code=policy_err_code) | ||
self.__handle_and_report_ext_handler_errors(handler_i, err, | ||
report_op=handler_i.operation, | ||
message=ustr(err), extension=extension, report=True) | ||
continue | ||
|
||
extension_allowed = policy_engine.should_allow_extension(ext_handler.name) | ||
if not extension_allowed: | ||
msg = "failed to {0} extension '{1}' because extension is not specified in allowlist. To {0}, " \ | ||
"add extension to the allowed list in the policy file ('{2}').".format(policy_op, | ||
ext_handler.name, | ||
conf.get_policy_file_path()) | ||
err = ExtensionPolicyError(msg, code=policy_err_code) | ||
self.__handle_and_report_ext_handler_errors(handler_i, err, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same question here about .status file for single config extensions |
||
report_op=handler_i.operation, | ||
message=ustr(err), extension=extension, report=True) | ||
|
||
# In case of extensions disabled, we skip processing extensions. But CRP is still waiting for some status | ||
# back for the skipped extensions. In order to propagate the status back to CRP, we will report status back | ||
# here with an error message. | ||
|
@@ -527,7 +567,11 @@ def handle_ext_handlers(self, goal_state_id): | |
continue | ||
|
||
# Process extensions and get if it was successfully executed or not | ||
extension_success = self.handle_ext_handler(handler_i, extension, goal_state_id) | ||
# If extension was blocked by policy, treat the extension as failed and do not process the handler. | ||
if not extension_allowed: | ||
extension_success = False | ||
else: | ||
extension_success = self.handle_ext_handler(handler_i, extension, goal_state_id) | ||
|
||
dep_level = self.__get_dependency_level((extension, ext_handler)) | ||
if 0 <= dep_level < max_dep_level: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,7 +22,7 @@ | |
from azurelinuxagent.common import logger | ||
from azurelinuxagent.common.event import WALAEventOperation, add_event | ||
from azurelinuxagent.common import conf | ||
from azurelinuxagent.common.exception import AgentError | ||
from azurelinuxagent.common.exception import AgentError, ExtensionError | ||
from azurelinuxagent.common.protocol.extensions_goal_state_from_vm_settings import _CaseFoldedDict | ||
from azurelinuxagent.common.utils.flexible_version import FlexibleVersion | ||
|
||
|
@@ -36,12 +36,6 @@ | |
_MAX_SUPPORTED_POLICY_VERSION = "0.1.0" | ||
|
||
|
||
class PolicyError(AgentError): | ||
""" | ||
Error raised during agent policy enforcement. | ||
""" | ||
|
||
|
||
class InvalidPolicyError(AgentError): | ||
""" | ||
Error raised if user-provided policy is invalid. | ||
|
@@ -51,6 +45,16 @@ def __init__(self, msg, inner=None): | |
super(InvalidPolicyError, self).__init__(msg, inner) | ||
|
||
|
||
class ExtensionPolicyError(ExtensionError): | ||
""" | ||
Error raised during agent extension policy enforcement. | ||
""" | ||
# TODO: when CRP adds terminal error code for policy-related extension failures, set that as the default code. | ||
def __init__(self, msg, inner=None, code=-1): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this default code be 1009 (terminal enable failure) for now? or just remove the default? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can remove the default |
||
msg = "Extension is disallowed by agent policy and will not be processed: {0}".format(msg) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In case where agent failed to parse policy, I'm not sure we should say 'Extension is disallowed by policy'. In this case, extension is disallowed because there's some issue reading or parsing the policy. I also am hesitant about 'agent policy' since policy is provided by customer |
||
super(ExtensionPolicyError, self).__init__(msg, inner, code) | ||
|
||
|
||
class _PolicyEngine(object): | ||
""" | ||
Implements base policy engine API. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this create .status files for single config extensions?