-
Notifications
You must be signed in to change notification settings - Fork 1k
POC: Implement OWASP security logging. #6689
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
base: main
Are you sure you want to change the base?
Conversation
…estart Implement OWASP structured logs in /var/log/cloud-init-security.log. Add security-related operations performed by cloud-init on behalf of user-data or platform meta-data: - user creation - user password change - system restart - system shutdown Default security log file can be changed by setting an alternative value for security_log_file in /etc/cloud/cloud.cfg(.d/*.cfg).
|
cc: @dbungert |
holmanb
left a comment
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.
Thanks for this @blackboxsw. First pass.
If the goal is for this to be cross-distro, then implementing this in the distro class doesn't seem optimal because distro methods are expected to be (and in this case are) overridden.
Also, is there a reason that the logger package cannot be used? Manually writing to files seems undesirable - I would have expected this to define a custom logger for this purpose.
Thank you for the type annotations. Besides just annotating the types, I'd like to see if we can also avoid unnecessary complexity - something that annotations can assist with. For example rather than checking an Optional parameter for trutheyness, we could instead avoid the possibility of None and pass a falsey value instead.
| # Create file with restricted permissions if it doesn't exist | ||
| if not os.path.exists(log_file): | ||
| util.ensure_file(log_file, mode=0o600, preserve_mode=False) | ||
|
|
||
| util.append_file(log_file, json_line, disable_logging=True) |
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.
This doesn't seem ideal. Was Python's builtin logger considered?
This complicates code in util and makes for a bunch of otherwise unnecessary logger file parameters.
| sec_log_user_created( | ||
| userid="cloud-init", | ||
| new_userid=name, | ||
| attributes={"snapuser": True, "sudo": True}, | ||
| ) |
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.
Intermixing code of different different purposes like this will lead to difficulty maintaining and auditing the code. I would prefer if we could find a cleaner design.
| LOG = logging.getLogger(__name__) | ||
|
|
||
| # Hard-coded application identifier per spec | ||
| APP_ID = "canonical.cloud_init" |
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.
Why the underscore? If no hyphen is allowed then I would prefer "canonical.cloudinit" over this.
| rotated_logs = [] | ||
| if not cfg or not isinstance(cfg, dict): | ||
| return logs | ||
| default_log = cfg.get("def_log_file") |
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.
The changes in this file seem unnecessary.
| def sec_log_system_shutdown( | ||
| userid: Optional[str] = None, | ||
| mode: Optional[str] = None, | ||
| delay: Optional[str] = None, | ||
| log_file: Optional[str] = DEFAULT_SECURITY_LOG, | ||
| ) -> None: |
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.
Why the unused parameters? Possibly same question elsewhere.
| userid: str, | ||
| new_userid: str, | ||
| attributes: Optional[Dict[str, Any]] = None, | ||
| log_file: Optional[str] = DEFAULT_SECURITY_LOG, |
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.
Why the log file parameters? This seems unnecessary.
| def sec_log_user_created( | ||
| userid: str, | ||
| new_userid: str, | ||
| attributes: Optional[Dict[str, Any]] = None, |
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.
Optional parameters often complicate type annotations unnecessarily. Can we restructure this to be cleaner? Same comment repeated throughout this code.
| util.logexc(LOG, "Failed to set password for %s", user) | ||
| raise e | ||
|
|
||
| # Log security event for password change |
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.
This comment seems unnecessary.
| cmd = ["chpasswd"] + (["-e"] if hashed else []) | ||
| subp.subp(cmd, data=payload) | ||
|
|
||
| # Log security event for each password change |
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.
This comment seems unnecessary.
| if params: | ||
| # Filter out None values and convert to strings | ||
| filtered_params = [str(p) for p in params if p is not None] | ||
| if filtered_params: |
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.
This conditional is unnecessary.
Provide an initial spike for logging OWASP formatted events in cloud-init for discussion. Integration tests will be added upon agreement for security logging procedures.
Proposed Commit Message
Additional Context
Test Steps
TODO: extend integration tests once initial discussion conclused
Merge type