Skip to content

Commit

Permalink
Remove schema errors from log (#1551)
Browse files Browse the repository at this point in the history
When schema errors are encountered, the section of userdata in question
gets printed to the cloud-init log. As this could contain sensitive
data, so log a generic warning instead and redirect user to run
cloud-init schema --system as root.

LP: #1978422
CVE: 2022-2084
  • Loading branch information
TheRealFalcon committed Jun 29, 2022
1 parent 4eab80c commit 4d467b1
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 11 deletions.
4 changes: 3 additions & 1 deletion cloudinit/cmd/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,9 @@ def main_init(name, args):

# Validate user-data adheres to schema definition
if os.path.exists(init.paths.get_ipath_cur("userdata_raw")):
validate_cloudconfig_schema(config=init.cfg, strict=False)
validate_cloudconfig_schema(
config=init.cfg, strict=False, log_details=False
)
else:
LOG.debug("Skipping user-data validation. No user-data found.")

Expand Down
15 changes: 12 additions & 3 deletions cloudinit/config/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ def validate_cloudconfig_schema(
schema: dict = None,
strict: bool = False,
strict_metaschema: bool = False,
log_details: bool = True,
):
"""Validate provided config meets the schema definition.
Expand All @@ -210,6 +211,9 @@ def validate_cloudconfig_schema(
logging warnings.
@param strict_metaschema: Boolean, when True validates schema using strict
metaschema definition at runtime (currently unused)
@param log_details: Boolean, when True logs details of validation errors.
If there are concerns about logging sensitive userdata, this should
be set to False.
@raises: SchemaValidationError when provided config does not validate
against the provided schema.
Expand All @@ -234,12 +238,17 @@ def validate_cloudconfig_schema(
errors += ((path, error.message),)
if errors:
if strict:
# This could output/log sensitive data
raise SchemaValidationError(errors)
else:
if log_details:
messages = ["{0}: {1}".format(k, msg) for k, msg in errors]
LOG.warning(
"Invalid cloud-config provided:\n%s", "\n".join(messages)
details = "\n" + "\n".join(messages)
else:
details = (
"Please run 'sudo cloud-init schema --system' to "
"see the schema errors."
)
LOG.warning("Invalid cloud-config provided: %s", details)


def annotated_cloudconfig_file(
Expand Down
20 changes: 14 additions & 6 deletions tests/integration_tests/modules/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,18 @@
- echo 'hi' > /var/tmp/test
"""

# The '-' in 'hashed-password' fails schema validation
INVALID_USER_DATA_SCHEMA = """\
#cloud-config
updates:
notnetwork: -1
apt_pipelining: bogus
users:
- default
- name: newsuper
gecos: Big Stuff
groups: users, admin
sudo: ALL=(ALL) NOPASSWD:ALL
hashed-password: asdfasdf
shell: /bin/bash
lock_passwd: true
"""


Expand Down Expand Up @@ -69,11 +76,12 @@ def test_invalid_userdata_schema(client: IntegrationInstance):
assert result.ok
log = client.read_from_file("/var/log/cloud-init.log")
warning = (
"[WARNING]: Invalid cloud-config provided:\napt_pipelining: 'bogus'"
" is not valid under any of the given schemas\nupdates: Additional"
" properties are not allowed ('notnetwork' was unexpected)"
"[WARNING]: Invalid cloud-config provided: Please run "
"'sudo cloud-init schema --system' to see the schema errors."
)
assert warning in log
assert "asdfasdf" not in log

result = client.execute("cloud-init status --long")
if not result.ok:
raise AssertionError(
Expand Down
23 changes: 22 additions & 1 deletion tests/unittests/config/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,10 +286,31 @@ def test_validateconfig_schema_non_strict_emits_warnings(self, caplog):
assert "cloudinit.config.schema" == module
assert logging.WARNING == log_level
assert (
"Invalid cloud-config provided:\np1: -1 is not of type 'string'"
"Invalid cloud-config provided: \np1: -1 is not of type 'string'"
== log_msg
)

@skipUnlessJsonSchema()
def test_validateconfig_schema_sensitive(self, caplog):
"""When log_details=False, ensure details are omitted"""
schema = {
"properties": {"hashed_password": {"type": "string"}},
"additionalProperties": False,
}
validate_cloudconfig_schema(
{"hashed-password": "secret"},
schema,
strict=False,
log_details=False,
)
[(module, log_level, log_msg)] = caplog.record_tuples
assert "cloudinit.config.schema" == module
assert logging.WARNING == log_level
assert (
"Invalid cloud-config provided: Please run 'sudo cloud-init "
"schema --system' to see the schema errors." == log_msg
)

@skipUnlessJsonSchema()
def test_validateconfig_schema_emits_warning_on_missing_jsonschema(
self, caplog
Expand Down

0 comments on commit 4d467b1

Please sign in to comment.