-
Notifications
You must be signed in to change notification settings - Fork 157
ROX-29232: Validate user-provided dockerConfigs for non-UTF-8 chars #15270
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
Conversation
Skipping CI for Draft Pull Request. |
Images are ready for the commit at d4453b1. To use with deploy scripts, first |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #15270 +/- ##
==========================================
- Coverage 49.24% 49.24% -0.01%
==========================================
Files 2578 2578
Lines 189182 189298 +116
==========================================
+ Hits 93158 93212 +54
- Misses 88688 88744 +56
- Partials 7336 7342 +6
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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.
Few top of mind thoughts
- This seems like it would work just fine, bit shocked we haven't run into this in the past.
- Is the issue only with gRPC such that k8s / CRI-O still work OK even when a secret has a 'non-utf-8' character in it? (ie: is it only ACS that cannot interpret this data)
- If so, wondering if worth looking at how k8s/cri-o handle this - perhaps mimcing any encoding / types / validation would be better? (granted introduces some other complexes on either end of the comms, and when persisting the data to Central DB may run into the same error during marshalling)
- Or perhaps there is some gRPC flag to not be strict on invalid utf-8 chars? <- Not so sure I like this - is a cover up
- Or perhaps
strings.ToValidUTF8
can help? <- this also makes me uneasy as the data is being changed.
Would it help to also add logging to the error message on either end of the comms to print the 'type' information of the message that failed to be marshalled/unmarshalled? (ie: error failed to marshall, bad utf8, in MsgFromSensor.SensorEvent_ImageIntegration) so that we would know (for example) it is a secret that had the bad data vs. a deployment vs. something else.
It is a second case like this that I am handling and I would love to have the information that you suggest. The tricky part here is that if there is an error returned from grpc (on receiving), then the However, it is possible to do that on the sending side. And I think, we should have it. |
I made a small test and looks like VT proto properly handles non-utf8 characters. From your example it looks proto is called instead of vt proto. This may happen because codec is not setup properly (in theory it should as it's in package protocompat
import (
"testing"
gogo "github.com/gogo/protobuf/proto"
"github.com/stackrox/rox/pkg/protoassert"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/proto"
"github.com/stackrox/rox/generated/storage"
)
var name = string([]byte{0xC0})
func TestUnmarshalGogo(t *testing.T) {
m := &storage.NamespaceMetadata{Name: name}
_, err := gogo.Marshal(m)
assert.EqualError(t, err, `proto: field ".Name" contains invalid UTF-8`)
}
func TestUnmarshalVT(t *testing.T) {
m := &storage.NamespaceMetadata{Name: name}
a, err := m.MarshalVT()
assert.NoError(t, err)
n := &storage.NamespaceMetadata{}
err = n.UnmarshalVT(a)
assert.NoError(t, err)
protoassert.Equal(t, m, n)
}
func TestUnmarshalProto(t *testing.T) {
m := &storage.NamespaceMetadata{Name: name}
_, err := proto.Marshal(m)
assert.EqualError(t, err, `string field contains invalid UTF-8`)
} |
@janisz thanks for sharing the insights! Do you have an idea how to verify that the codec is setup properly? |
Agree not possible on the receiving side, would be on the sending side. |
We can create a unit test for straming like here https://github.com/stackrox/stackrox/pull/14083/files#diff-80aadd25196a5db848dfb2c5d9240d09512010efc442f90766ac247fbcfc4180 |
I am closing this PR. The reasons for that are in the PR description in the "Update" section. |
Temporary, one can use branch
|
|
GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
---|---|---|---|---|---|
17208197 | Triggered | Generic High Entropy Secret | 9da1da2 | sensor/kubernetes/listener/resources/secrets_test.go | View secret |
17207583 | Triggered | Kubernetes Docker Secret | 8f6765e | sensor/kubernetes/listener/resources/secrets_test.go | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
This is a dummy secret created only for the tests. |
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.
Hey @vikin91 - I've reviewed your changes - here's some feedback:
- In the update/delete flows you drop the event entirely when all registries are invalid, which can leave stale image integrations behind—consider emitting a delete event in that case to clean up existing integrations.
- The function name
validateSecret
is misleading since it only validates a single DockerConfig entry; consider renaming it (e.g.validateDockerConfigEntry
) and extracting common UTF-8 checks for reuse. - Rather than ad-hoc UTF-8 checks on registry, username, and password, you may want to enforce UTF-8 validation at the gRPC/message boundary or switch to byte fields to avoid similar crashes elsewhere.
Here's what I looked at during the review
- 🟡 General issues: 1 issue found
- 🟡 Testing: 1 issue found
- 🟢 Complexity: all looks good
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
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.
Out of curiosity, do you know what happens in K8s? As in, does K8s see these registries as valid/are they actually valid?
Unfortunately, I don't know. I would need to do an experiment. |
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.
Is it worth preventing the connection from being killed for any invalid message? Will that be too much overhead? Since this can occur for any message sent to Central from Sensor (or vice versa).
I realize that k8s does some degree of validation for more structured fields (such as resource names) - should we treat all info from k8s events as 'untrusted input'?
rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
@dcaravel I addressed some of the issues; others I commented on as I am not sure how to incorporate them into this PR. Do you think we can merge this for 4.8 or shall we improve more? |
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.
I think we need a changelog entry for this with information that we do not support non UTF-8 docker configs.
Co-authored-by: David Caravello <119438707+dcaravel@users.noreply.github.com>
rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
@dcaravel I acknowledge that this PR is not fixing all the issues, but I believe that having it in 4.8 would be valuable. |
I'm reviewing right now - give me 10 mins |
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.
LGTM
@vikin91: The following test failed, say
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-sigs/prow repository. I understand the commands that are listed here. |
The integration tests failure looks unrelated:
|
Description
This PR is to prevent GRPC marshaling and unmarshaling errors (leading to crash of the GRPC connection) when data modeled as
string
in the proto contain non-UTF-8 characters.Note: this is a very limited fix, as it only validates selected types of data provided from the user. It is still possible that other not yet validated user-provided inputs may lead to grpc crash due to non-UTF-8 characters.
Update⚠️
This PR
won'thelp with the problem. Here is what I know so far:It is impossible to read a non-UTF-8 characters from the orchestrator (from a secret, configmap, annotation etc) and crash the grpc connection. Reading it from k8s makes it non-lethal, as most probably the non-utf-8 characters are fixed in the process of reading or writing to the secret.Thus: Validation of the secrets read from k8s makes no sense and this PR will be closed.
Update 2⚠️
Apparently storing secrets with non-uft-8 characters in k8s to make them harmless works only for some selected non-utf-8 characters. @dcaravel found that the following secret can lead to a crash even if stored and read from k8s:
User-facing documentation
Testing and quality
Automated testing
How I validated my change
Reproduction
First, I hardcoded a dockerConfig secret (in the code) with non-UTF-8 characters*. I did something like:
around this place:
stackrox/sensor/kubernetes/listener/resources/secrets.go
Line 315 in 0707d4a
and run that with local sensor:
then in Sensor logs I observed the following error:
*) I did that, because I am unable to type a non-UTF-8 character from my keyboard directly into a k8s secret.