Skip to content
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

Add secret masking functions to be called in logger and directly #345

Merged
merged 6 commits into from
Nov 4, 2022

Conversation

mickmcgrath13
Copy link
Contributor

@mickmcgrath13 mickmcgrath13 commented Nov 3, 2022

Description

Add configuration in the bitops-level bitops.config to add masks based on regular expressions.

Todo

  • add a setting for turning masking on or off (on by default, include a warning if it's turned off)
  • There's a TODO to look into a library and swap out the regex format if necessary, but I think this is a good start
  • ops-repo bitops.config.yaml support for custom masking at the ops-repo level
  • docs

Fixes #208

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

How Has This Been Tested?

Tested locally with BITOPS_KUBECONFIG_BASE64 (see this pr for the local development setup used)

Logs
without change:

~#~#~#~BITOPS ENVIRONMENT VARIABLES~#~#~#~
	BITOPS_DEFAULT_ROOT_DIR=_default
	BITOPS_DIR=/opt/bitops
	BITOPS_ENVIRONMENT=prod
	BITOPS_ENVROOT=/tmp/tmplcry4xqb/prod
	BITOPS_FAIL_FAST=True
	BITOPS_KUBECONFIG_BASE64=uueagqwugv8a4isbviaw9ah49h9g39vba4ba4v9wvofgairgw

with changes:

~#~#~#~BITOPS ENVIRONMENT VARIABLES~#~#~#~
	BITOPS_DEFAULT_ROOT_DIR=_default
	BITOPS_DIR=/opt/bitops
	BITOPS_ENVIRONMENT=prod
	BITOPS_ENVROOT=/tmp/tmplcry4xqb/prod
	BITOPS_FAIL_FAST=True
	BITOPS_KUBECONFIG_BASE64=*******

Test Configuration: (see below)

  • BitOps image tag used: 2.1.0
  • Tool/plugin: n/a

mask config: modified the omnibus bitops.config.yaml to include new mask configuration
command:

docker run --rm --name bitops \
-e AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID}" \
-e AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY}" \
-e AWS_SESSION_TOKEN="${AWS_SESSION_TOKEN}" \
-e AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}" \
-e BITOPS_ENVIRONMENT="prod" \
-e SKIP_DEPLOY_TERRAFORM="true" \
-e SKIP_DEPLOY_HELM="true" \
-e DEFAULT_FOLDER_NAME="_default" \
-e BITOPS_KUBECONFIG_BASE64="${BITOPS_KUBECONFIG_BASE64}" \
-e PYTHONUNBUFFERED=1 \
-v /path/to/bitops:/opt/bitops \
-v /path/to/operations-repo:/opt/bitops_deployment \
-v /path/to/bitops/prebuilt-config/omnibus/bitops.config.yaml:/opt/bitops/bitops.config.yaml \
-v /opt/bitops/scripts/plugins/aws \
-v /opt/bitops/scripts/plugins/cloudformation \
-v /opt/bitops/scripts/plugins/kubectl \
-v /opt/bitops/scripts/plugins/ansible \
-v /path/to/bitops-plugins/helm:/opt/bitops/scripts/plugins/helm \
-v /path/to/bitops-plugins/terraform:/opt/bitops/scripts/plugins/terraform \
--entrypoint "python3" \
bitovi/bitops:2.1.0 \
/opt/bitops/scripts/main.py deploy

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation

scripts/plugins/logging.py Outdated Show resolved Hide resolved
scripts/plugins/logging.py Outdated Show resolved Hide resolved
}


# TODO: move to its own file so it can be used by plugins and before/after hooks
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and was thinking of mentioning that this would be best in the utilities module. The trick is that would create a cyclic dependency.

If we really want to make this function available, then I'd recommend we create a bare-utilities.py file that strictly maintains a "no app specific import" rule. This would mean that it would be imported by all other app-specific modules.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PhillypHenning do you mind creating an issue for this?

@PhillypHenning
Copy link
Contributor

@mickmcgrath13 I'm going to merge this unless you stop me within the next hour

@PhillypHenning PhillypHenning merged commit d5f625e into main Nov 4, 2022
@PhillypHenning PhillypHenning deleted the 208-mask-sensitive-output branch November 4, 2022 15:06
@PhillypHenning
Copy link
Contributor

@mickmcgrath13

I ran into this issue

#8 0.955   File "/opt/bitops/scripts/plugins/logging.py", line 84, in format
#8 0.955     record.msg = mask_message(record.msg)
#8 0.955   File "/opt/bitops/scripts/plugins/logging.py", line 44, in mask_message
#8 0.955     for config_item in BITOPS_logging_masks:
#8 0.955 TypeError: 'NoneType' object is not iterable

I've added the following to the logging.py file to ensure this doesn't happen;

if BITOPS_logging_masks is None:
        return message

This is fixed in #347

@arm4b arm4b changed the title [WIP] closes #298 - add masking functions to be called in logger and directly Add secret masking functions to be called in logger and directly Nov 7, 2022
Copy link
Member

@arm4b arm4b left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left my opinions about this feature, but it works in optimistic examples and is a nice start! 👍

Outside of heuristics and rules from 3rd party libs we may also want to define a list of secrets, take the ENV var value and replace it in the output too so it catches the real secret string.

From the evident next steps we're missing other secret vars for all the plugins (AWS, etc) in the fleet https://github.com/bitops-plugins/ and it is worth adding some minimal documentation.


res_str = message
for config_item in BITOPS_logging_masks:
# TODO: use a library here?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, totally.

It's good to have something initially working, but IMO it doesn't solve the secrets problem technically with such approach, but rather creates a visibility of solving it which is dangerous in security context.
Trying to mask the secrets this way might be not production ready, and also hard to call user-friendly with the new bitops config.

We might leverage external rules like: https://github.com/Yelp/detect-secrets/tree/master/detect_secrets/plugins and heuristics from the tool that might already having secrets detection.

Ex: https://github.com/Yelp/detect-secrets/blob/master/detect_secrets/plugins/github_token.py#L15

Comment on lines +18 to +27
- # regex to search
# looks for `BITOPS_KUBECONFIG_BASE64={string}`
search: (.*BITOPS_KUBECONFIG_BASE64.*\=)(.*\n)
# replace the value part
replace: '\1*******\n'
- # regex to search
# looks for `The namespace kube-system exists`
search: (.*The namespace )(kube-system)( exists.*)
#replace kube-system
replace: '\1*******\3'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it really close the #208?

Was the BITOPS_KUBECONFIG_BASE64 the only available secret we're passing or are there any other secret vars from the plugins?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right that it does not close #208. This PR was to set up a decent approach, but there's certainly more to do for specific secrets. Thx for re-opening #208.

masks:
- # regex to search
# looks for `BITOPS_KUBECONFIG_BASE64={string}`
search: (.*BITOPS_KUBECONFIG_BASE64.*\=)(.*\n)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're targeting beginners, I wouldn't expose regex setting in the BitOps config as it brings complexity to the user's side. It's enough to list 10 regex rules to make everything look complicated and repell someone using it.

Other options:

  1. Just list the secret vars in bitops core or config. No regex, just BITOPS_KUBECONFIG_BASE64, AWS_SECRET_KEY, etc. and do the rest filtering on the BitOps side.
  2. auto-detect secrets in log via heuristics and rules from libs like https://github.com/Yelp/detect-secrets/tree/master/detect_secrets/plugins
  3. allow specifying extra secret names on top of default/hardcoded
secrets:
  - BITOPS_KUBECONFIG_BASE64
  - AWS_SECRET_ACCESS_KEY
  - AWS_ACCESS_KEY_ID
  - AWS_SESSION_TOKEN

Alternatively, allow defining secrets on BitOps Plugin level and process in the code so the secret definition is pluggable.

# looks for `BITOPS_KUBECONFIG_BASE64={string}`
search: (.*BITOPS_KUBECONFIG_BASE64.*\=)(.*\n)
# replace the value part
replace: '\1*******\n'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to omit the "replace" part, defaulting it to just ****.

@@ -13,6 +13,18 @@ bitops:
filename: bitops-run # log filename
err: bitops.logs # error logs filename
path: /var/logs/bitops # path to log folder
# Define the secrets to mask
masks:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

secrets:

@mickmcgrath13
Copy link
Contributor Author

@armab I've captured your comments here: #208 so we can coordinate the efforts/other tickets

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Parse passwords / creditentials out of logging output
3 participants