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 credentials filter to entrypoint logger #4837

Closed

Conversation

Useurmind
Copy link

@Useurmind Useurmind commented May 5, 2022

Changes

This PR is related to #3373. The issue was closed by your bot but the topic is still relevant to us.

It solves the problem that secret values are printed to the output log. All secrets contained in the namespace of the pod will be redacted. The pod needs a service account token with permissions to read out all secret in the namespace from the api server.

I added a credential filter to the runner app of tekton steps. It reads out all secrets from the namespace of the pod and redacts them from the output log.

This is currently a draft, I would be happy to polish it if you have interest in adopting this approach.

/kind feature

Submitter Checklist

As the author of this PR, please check off the items in this checklist:

  • Docs included if any changes are user facing
  • Tests included if any functionality added or changed
  • Follows the commit message standard
  • Meets the Tekton contributor standards (including
    functionality, content, code)
  • Release notes block below has been filled in
    (if there are no user facing changes, use release note "NONE")

Release Notes

add credential filter that can be activated via a new feature flag `enable-logging-credentials-filter`

@tekton-robot tekton-robot added release-note Denotes a PR that will be considered when it comes time to generate release notes. kind/feature Categorizes issue or PR as related to a new feature. labels May 5, 2022
@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented May 5, 2022

CLA Signed

The committers listed above are authorized under a signed CLA.

@tekton-robot tekton-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels May 5, 2022
@tekton-robot
Copy link
Collaborator

Hi @Useurmind. Thanks for your PR.

I'm waiting for a tektoncd member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@Useurmind
Copy link
Author

Any interest in this feature?

@afrittoli
Copy link
Member

/ok-to-test

@tekton-robot tekton-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels May 25, 2022
@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
pkg/credentials/filter/credentials_detection.go Do not exist 0.0%
pkg/credentials/filter/credentials_filter.go Do not exist 100.0%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%

@afrittoli
Copy link
Member

Thanks @Useurmind for your PR!
I think there is interest in the feature, it may be something that we let user control via a feature flag?
I'm sorry about the slow response - between KubeCon and cdCon it's a busy conference time :D

/cc @imjasonh @vdemeester

@Useurmind
Copy link
Author

Then I will start implementing a feature toggle for it and will see that I add some tests.

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
pkg/credentials/filter/credentials_detection.go Do not exist 0.0%
pkg/credentials/filter/credentials_filter.go Do not exist 100.0%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
pkg/apis/config/feature_flags.go 88.0% 86.5% -1.5
pkg/credentials/filter/credentials_detection.go Do not exist 0.0%
pkg/credentials/filter/credentials_filter.go Do not exist 100.0%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
pkg/apis/config/feature_flags.go 88.0% 86.5% -1.5
pkg/credentials/filter/credentials_detection.go Do not exist 0.0%
pkg/credentials/filter/credentials_filter.go Do not exist 100.0%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%

@Useurmind
Copy link
Author

So I started looking into this feature and implementing a feature flag for it. Currently I am not sure how a feature flag may be best implemented for this.

I have found the following points:

  1. feature flag config map is only read and used in controller
  2. but credential filtering is done in the entrypoint binary during task runtime
  3. credentials filter needs a service account token that can read secrets and that is something which needs to be ensured when a pipeline is run

Point 1 and 2 could be solved handing down an argument or setting an environment variable to the entrypoint from the controller.

Point 3 probably must be solved by documenting the requirements for the credentials filter, so that pipeline creators can pay attention to it.

Does that approach make sense or is there an easier way?

@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented May 27, 2022

CLA Signed

The committers listed above are authorized under a signed CLA.

  • ✅ login: Useurmind / name: Jochen Grün (80aea82)

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 81.5% 65.9% -15.6
pkg/apis/config/feature_flags.go 88.0% 86.5% -1.5
pkg/credentials/filter/credentials_detection.go Do not exist 0.0%
pkg/credentials/filter/credentials_filter.go Do not exist 100.0%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/pod/pod.go 88.3% 87.8% -0.5

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 81.5% 63.4% -18.1
pkg/apis/config/feature_flags.go 88.0% 86.5% -1.5
pkg/credentials/filter/credentials_detection.go Do not exist 0.0%
pkg/credentials/filter/credentials_filter.go Do not exist 100.0%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/pod/pod.go 88.3% 87.8% -0.5

@imjasonh
Copy link
Member

The pod needs a service account token with permissions to read out all secret in the namespace from the api server.

This part worries me a bit. Does this feature require that all TaskRun pods now have more permissions than before, to be able to tell what to redact? That seems valuable, but it also may mean that TaskRuns that, e.g., execute kubectl get secrets will now be able to get all those secrets, unless we take extra steps to stop them.

Could this somehow query "all accessible secrets" instead, and redact whatever it can find, instead of requiring new access to all secrets in its namespace?

I wonder if this could also lead to more load on the API server, since every TaskRun would start by fetching all secrets in its namespace, which for clusters running lots of TaskRuns could cause problems.

Not saying we shouldn't do this -- redacting secrets would be great -- just curious about some of the implications around limiting access and being mindful to reduce API traffic.

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 81.5% 65.9% -15.6
pkg/apis/config/feature_flags.go 88.0% 86.5% -1.5
pkg/credentials/filter/credentials_detection.go Do not exist 0.0%
pkg/credentials/filter/credentials_filter.go Do not exist 100.0%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/pod/pod.go 88.3% 87.8% -0.5

@Useurmind
Copy link
Author

You are correct in your understanding Jason. The pods can only redact secrets that they know and have access to. And they will query the API server for this.

The current implementation uses the go-client to do so. I am not entirely sure but I suspect that the client will return only the secrets that the service account has access to. If not we can implement it in this way. That would mean if the service account has no access to secrets, he will not be able to redact them properly.

The performance implications are as you say. But as this is hidden behind a feature flag, it should not harm existing installations. If the feature is not enabled not communication to the api server takes place.

Btw. as far as I understand the permission concept in k8s a user can either see all secrets in a namespace or none. If you want to hide resources from a user only partially, you need to put them in different namespaces. Seeing can be limited to listing or reading them. But in the end its all or none.

@Useurmind
Copy link
Author

Some more things to consider:

I would advice to extend this in the future so multiple secret detection algorithms can be used. Secrets have so many sources meanwhile that it becomes hard to configure one that works for everyone. This is a rather simple approach to read all secrets from the namespace. Others could be:

  • Read all secrets referenced in environment variables of your pod
  • Read all secrets referenced in volume mounts via csi drivers (this could depend on the csi secret provisioner)
  • Read secrets from secret parameter values of the task itself
  • ... more?

Should we consider implementing one of those? Then the pod would only need access to its own resource and could detect the secrets from files and environment variables. But I am not sure it is as complete as the approach above. It is also more complicated to implement.

@Useurmind
Copy link
Author

I thought about the implenentation again over the weekend. If there is currently no contact between tekton pipeline run pods and the API server it would be a grave error to require this in the future. It makes the whole design of the pipelines more complicated and the behaviour less stable and harder to predict.

Therefore, I would suggest the following approach, similar to my previous post but not the same:

  • The controller knows the created pods ressources exactly, he does not even need to contact the API server to read it
  • The controller can extract information about which secrets are linked into the pod, examples (not the actual secrets, just the locations):
    • environment variables: based on the secret ref value in the pod
    • files: based on CSI providers and secret refs volumes
  • This information is handed to the entrypoint which can extract the secrets from the locations and use them to redact them from the output

Much more complicated than the current implementation, but more in line with the current design and easier to reason about regarding the permissions because the pipeline pod will not need any new permissions.

@tekton-robot tekton-robot removed the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label May 30, 2022
@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 84.4% 83.3% -1.0
pkg/apis/config/feature_flags.go 80.3% 79.5% -0.8
pkg/credentials/filter/credentials_filter.go Do not exist 93.9%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/credentials/filter/secret_detection.go Do not exist 72.2%
pkg/credentials/filter/secret_extraction.go Do not exist 89.7%
pkg/credentials/filter/secret_locations.go Do not exist 0.0%
pkg/pod/pod.go 89.5% 87.6% -1.9

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 82.8% 84.4% 1.6
pkg/apis/config/feature_flags.go 80.3% 79.5% -0.8
pkg/credentials/filter/credentials_filter.go Do not exist 93.9%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/credentials/filter/secret_detection.go Do not exist 72.2%
pkg/credentials/filter/secret_extraction.go Do not exist 89.7%
pkg/credentials/filter/secret_locations.go Do not exist 0.0%
pkg/pod/pod.go 89.5% 87.6% -1.9

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 82.8% 84.4% 1.6
pkg/apis/config/feature_flags.go 80.3% 79.5% -0.8
pkg/credentials/filter/credentials_filter.go Do not exist 93.9%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/credentials/filter/secret_detection.go Do not exist 72.2%
pkg/credentials/filter/secret_extraction.go Do not exist 91.7%
pkg/credentials/filter/secret_locations.go Do not exist 0.0%
pkg/pod/pod.go 89.5% 87.6% -1.9

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 82.8% 84.4% 1.6
pkg/apis/config/feature_flags.go 80.3% 79.5% -0.8
pkg/credentials/filter/credentials_filter.go Do not exist 93.9%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/credentials/filter/secret_detection.go Do not exist 72.2%
pkg/credentials/filter/secret_extraction.go Do not exist 91.7%
pkg/credentials/filter/secret_locations.go Do not exist 0.0%
pkg/pod/pod.go 89.5% 87.6% -1.9

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 84.4% 83.3% -1.0
pkg/apis/config/feature_flags.go 80.3% 79.5% -0.8
pkg/credentials/filter/credentials_filter.go Do not exist 93.9%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/credentials/filter/secret_detection.go Do not exist 72.2%
pkg/credentials/filter/secret_extraction.go Do not exist 91.7%
pkg/credentials/filter/secret_locations.go Do not exist 0.0%
pkg/pod/pod.go 89.5% 87.6% -1.9

@tekton-robot tekton-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 5, 2022
}

// NewRingBuffer creates a RingBuffer with the given length.
func NewRingBuffer(length int) *RingBuffer {
Copy link
Member

Choose a reason for hiding this comment

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

I agree that we don't want to add a new dependency like the one you listed, but this still adds complexity to an already large PR. Would it be possible to either use a plain slice of bytes as a buffer, or move the ring buffer implementation into its own PR?

}

// Close will write remaining bytes from the internal buffer to the output stream.
// The remaining bytes will not be filtered.
Copy link
Member

Choose a reason for hiding this comment

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

why not filter the bytes remaining in the buffer? Couldn't the buffer still contain a secret that is shorter than the longest one?

Copy link
Author

Choose a reason for hiding this comment

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

I had the misconception that there could be no secrets anymore in the remaining bytes. But that is wrong. I implemented a test that proved exactly that and added some filtering to the close method.

@@ -168,12 +210,19 @@ func (rr *realRunner) Run(ctx context.Context, args ...string) error {
// be used for multiple streams if desired.
// The behavior of the Reader is the same as io.TeeReader - reads from the pipe
// will be written to the file.
func newTeeReader(pipe func() (io.ReadCloser, error), path string) (*namedReader, error) {
func newTeeReader(pipe func() (io.ReadCloser, error), path string, writer io.WriteCloser) (*namedReader, error) {
Copy link
Member

Choose a reason for hiding this comment

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

This function docstring needs some updates; some of the commentary now belongs on getFileWriter.

Copy link
Author

Choose a reason for hiding this comment

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

updated the doc strings

@tekton-robot tekton-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jan 13, 2023
@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 82.8% 84.4% 1.6
pkg/apis/config/feature_flags.go 87.3% 86.5% -0.7
pkg/credentials/filter/credentials_filter.go Do not exist 94.7%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/credentials/filter/secret_detection.go Do not exist 72.2%
pkg/credentials/filter/secret_extraction.go Do not exist 91.7%
pkg/credentials/filter/secret_locations.go Do not exist 0.0%
pkg/pod/pod.go 91.8% 90.2% -1.6

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage-df to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 82.8% 84.4% 1.6
pkg/apis/config/feature_flags.go 87.3% 86.5% -0.7
pkg/credentials/filter/credentials_filter.go Do not exist 94.7%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/credentials/filter/secret_detection.go Do not exist 72.2%
pkg/credentials/filter/secret_extraction.go Do not exist 91.7%
pkg/credentials/filter/secret_locations.go Do not exist 0.0%
pkg/pod/pod.go 91.8% 90.2% -1.6

This adds a filter for secret values to the logging mechanism in the pipeline entrypoint.

The secrets locations in the form of environment variables and files are detected by the controller
creating the pipeline step pod. The information about secrets attached to that pod are given
to the entrypoint as a json file.

From there the entrypoint will read the secret values from the given locations and redact all
occurences from the output log.
@Useurmind Useurmind requested review from lbernick and removed request for vdemeester, imjasonh and dlorenc January 13, 2023 11:42
@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 82.8% 84.4% 1.6
pkg/apis/config/feature_flags.go 87.3% 86.5% -0.7
pkg/credentials/filter/credentials_filter.go Do not exist 94.7%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/credentials/filter/secret_detection.go Do not exist 72.2%
pkg/credentials/filter/secret_extraction.go Do not exist 91.7%
pkg/credentials/filter/secret_locations.go Do not exist 0.0%
pkg/pod/pod.go 91.8% 90.2% -1.6

@tekton-robot
Copy link
Collaborator

The following is the coverage report on the affected files.
Say /test pull-tekton-pipeline-go-coverage-df to re-run this coverage report

File Old Coverage New Coverage Delta
cmd/entrypoint/runner.go 82.8% 84.4% 1.6
pkg/apis/config/feature_flags.go 87.3% 86.5% -0.7
pkg/credentials/filter/credentials_filter.go Do not exist 94.7%
pkg/credentials/filter/ring_buffer.go Do not exist 100.0%
pkg/credentials/filter/secret_detection.go Do not exist 72.2%
pkg/credentials/filter/secret_extraction.go Do not exist 91.7%
pkg/credentials/filter/secret_locations.go Do not exist 0.0%
pkg/pod/pod.go 91.8% 90.2% -1.6

@tekton-robot
Copy link
Collaborator

@Useurmind: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-tekton-pipeline-build-tests 82e897c link true /test pull-tekton-pipeline-build-tests

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

@tekton-robot tekton-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jan 28, 2023
@tekton-robot
Copy link
Collaborator

@Useurmind: PR needs rebase.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@jerop
Copy link
Member

jerop commented Apr 20, 2023

closing old pull requests, please feel free to reopen if you pick up this work!

@jerop jerop closed this Apr 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/feature Categorizes issue or PR as related to a new feature. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants