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 more validations to trust-policy parsing #43

Merged
merged 4 commits into from
May 26, 2022

Conversation

rgnote
Copy link
Contributor

@rgnote rgnote commented May 12, 2022

Changes:

  1. Added Registry Scope validations using the regex from distribution spec
  2. Added DN validations using go-ldap package
  3. Moved the policy document validation logic to sub-functions for better readability
  4. Moved the verification utility functions to helpers.go

Testing:
Added more unit tests and extensively tested the logic with local dummy policy files

Signed-off-by: rgnote 5878554+rgnote@users.noreply.github.com

Signed-off-by: rgnote <5878554+rgnote@users.noreply.github.com>
@rgnote rgnote requested a review from a team May 12, 2022 01:33
go.mod Outdated
@@ -6,3 +6,8 @@ require (
github.com/golang-jwt/jwt/v4 v4.4.1
github.com/opencontainers/go-digest v1.0.0
)

require (
github.com/go-ldap/ldap v3.0.3+incompatible // indirect
Copy link
Member

Choose a reason for hiding this comment

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

How is that ldap is marked as indirect when it is directly referenced in our code?

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 should have run go mod tidy. Also, I realized that I should use go-ldap v3 as mentioned here. Thanks for pointing this out. Will raise a new revision for this PR.

Signed-off-by: rgnote <5878554+rgnote@users.noreply.github.com>
@@ -3,6 +3,13 @@ module github.com/notaryproject/notation-go
go 1.17

require (
github.com/go-ldap/ldap/v3 v3.4.3
Copy link

Choose a reason for hiding this comment

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

go-ldap has a dependency on github.com/Azure/go-ntlmssp, but the functionality we need, DN validation does not. Is there a way to avoid this transitive dependency? Is the transitive dependency dropped during build as we do not use any types from github.com/Azure/go-ntlmssp?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

AFAIK, final build will only include the specific methods and their dependencies. Although I could not confirm this with official Go docs, I found multiple online forums confirming this. Seems like https://github.com/jondot/goweight could help us see what's included in the final build. I added it to my TODO list to revisit later.

Copy link
Member

Choose a reason for hiding this comment

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

unpopular opinion: Pulling in github.com/go-ldap/ldap, which is a library to talk with LDAP servers, just for validating a DN, seems like using a sledgehammer to crack a nut.

I would argue it's better just to copy ldap.ParseDN, and related tests, into notation-go and remove that dependency.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@qmuntal If we consume the whole package in our builds (like in java), then I agree with what you said. Thanks to Go static linking, our build will only include dn.ParseDN and it's dependencies. I prefer to keep a dependency on go-ldap to ensure we get the updates and security fixes. Also, go-ldap is the most popular library for ldap in Go, I'm not too worried about having a dependency on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Besides, I want to give them the credit rather than simply copying their code :)

Copy link
Member

@qmuntal qmuntal May 17, 2022

Choose a reason for hiding this comment

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

I'm not that concerned about binary size, as Go is really good at prunning unnecessary code. I'm worried about having a sane dependency tree. Keeping it to the bare minimum is always a plus, even if it means duplicating code.

That said, this particular dependency is not a red line for me.

Copy link

Choose a reason for hiding this comment

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

One concern I had was, we would see patch updates to this package more frequently from go-ldap/ldap package than we'd be actually impacted, as we are using a single type from the whole package. What is generally the process to handle patch updates to dependencies, will dependabot make this simpler?

@rgnote it's possible to copy a code files into our repo and still provide correct attribution to source repo.

I'd prefer copying the code in this case, it's not a one way decision, we can change it the other way if we wanted to later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tracking this in #45

}

// validateDistinguishedName validates if a DN name parsable and follows Notary V2 rules
func validateDistinguishedName(name string) error {
Copy link

@gokarnm gokarnm May 13, 2022

Choose a reason for hiding this comment

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

IMO, this method should move into notation-core-go. All X509 related parsing, validation, cert chain validation logic should be pushed there.

On second thought, this is Notary V2 specific DN validation based on what we allow in trust policy, so seems appropriate here.

Copy link

Choose a reason for hiding this comment

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

Should this method and validateRegistryScopeFormat be part of policy.go, they are only used in the context of validating a trust policy statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These helpers are for policy validation but I wanted to move them to a helper file so that policy.go is cleaner and deals with higher level functionality like policy verification. There is no side effect of having these methods in a helper class as Go package is a closure of everything under the package directory.

dn, err := ldapv3.ParseDN(name)

if err != nil {
return fmt.Errorf("distinguished name (DN) %q is not valid, make sure it is following rfc4514 standard", name)
Copy link

Choose a reason for hiding this comment

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

Suggested change
return fmt.Errorf("distinguished name (DN) %q is not valid, make sure it is following rfc4514 standard", name)
return fmt.Errorf("distinguished name (DN) %q is not valid, it must contain 'C', 'ST', and 'O' RDN attributes at a minimum, and follow RFC 4514 standard", name)

Comment on lines 59 to 64
// Verify there are no duplicate RDNs (multi-valdued RDNs are not supported)
for key := range rDnCount {
if rDnCount[key] > 1 {
return fmt.Errorf("distinguished name (DN) %q has duplicate RDNs, DN can only have unique RDNs", name)
}
}
Copy link

Choose a reason for hiding this comment

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

Duplicate is different from multi valued RDN, correct?
Multi-valued - OU=Sales+CN=J. Smith,DC=example
Duplicate -OU=Sales,DC=example,DC=net

Copy link

Choose a reason for hiding this comment

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

End customers may not be familiar with terminology RDN

Suggested change
// Verify there are no duplicate RDNs (multi-valdued RDNs are not supported)
for key := range rDnCount {
if rDnCount[key] > 1 {
return fmt.Errorf("distinguished name (DN) %q has duplicate RDNs, DN can only have unique RDNs", name)
}
}
// Verify there are no duplicate RDNs (multi-valdued RDNs are not supported)
for key := range rDnCount {
if rDnCount[key] > 1 {
return fmt.Errorf("distinguished name (DN) %q has duplicate RDN attribute for %q, DN can only have unique RDN attributes", name, key )
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

go-ldap does support multi-valued RDNs, hence notation-go lib can also support them. However, we should reject duplicate RDNs (OU=Sales,DC=example,DC=net) as there is no usecase for them in notary V2.

Copy link

Choose a reason for hiding this comment

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

We want notation-go lib to not support multi-valued RDNs as they are not commonly used, and confusing for end customers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed

// Verify mandatory fields are present
for _, field := range mandatoryFields {
if rDnCount[field] != 1 {
return fmt.Errorf("distinguished name (DN) %q has no mandatory RDN for %q", name, field)
Copy link

Choose a reason for hiding this comment

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

Suggested change
return fmt.Errorf("distinguished name (DN) %q has no mandatory RDN for %q", name, field)
return fmt.Errorf("distinguished name (DN) %q has no mandatory RDN attribute for %q, it must contain 'C', 'ST', and 'O' RDN attributes at a minimum", name, field)

@@ -3,6 +3,13 @@ module github.com/notaryproject/notation-go
go 1.17

require (
github.com/go-ldap/ldap/v3 v3.4.3
Copy link

Choose a reason for hiding this comment

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

One concern I had was, we would see patch updates to this package more frequently from go-ldap/ldap package than we'd be actually impacted, as we are using a single type from the whole package. What is generally the process to handle patch updates to dependencies, will dependabot make this simpler?

@rgnote it's possible to copy a code files into our repo and still provide correct attribution to source repo.

I'd prefer copying the code in this case, it's not a one way decision, we can change it the other way if we wanted to later.

Signed-off-by: rgnote <5878554+rgnote@users.noreply.github.com>
@rgnote
Copy link
Contributor Author

rgnote commented May 19, 2022

@qmuntal @gokarnm Addressed both your comments

Copy link
Member

@qmuntal qmuntal left a comment

Choose a reason for hiding this comment

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

LGTM!

Signed-off-by: rgnote <5878554+rgnote@users.noreply.github.com>
@rgnote
Copy link
Contributor Author

rgnote commented May 24, 2022

@gokarnm @qmuntal
Included two more validations in the latest version

  1. Throw error if there are any overlapping DNs in trustedIdentities
  2. Throw error if there are multi-valued RDNs in a DN

Copy link
Contributor

@NiazFK NiazFK left a comment

Choose a reason for hiding this comment

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

LGTM

@NiazFK NiazFK merged commit 2c9a8b0 into notaryproject:main May 26, 2022
@iamsamirzon iamsamirzon added this to the RC-1 milestone Jul 14, 2022
@dtzar dtzar modified the milestones: RC-1, alpha-3 Jul 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

6 participants