-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Deny location mapping in case of specific errors #95
Conversation
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.
There are two problems I see with this change:
- Misconfigured annotations should be a server error (5xx), not client.
There are a few reasons for this. These errors are actually server configuration problems, so that's more honest.
More importantly, most monitoring/notification systems ignore 4xx (as you must in the day of mass internet scanning, brute forcing, and DoSing), so the error is far less likely to be noticed by the operator.
- There's still no error printed at a reasonable V. The message is nice (thanks!), but if it's printed at V5 no one will see it.
I'm okay with 2 in a followup. 1 I think needs to be addressed.
I choose 403 because most of the annotations are related to security. |
500 or 503, probably 503 I think we should also have a similar error for all annotations, even those not closely related to security, but these are definitely the most important ones to cover. |
I think we can add an event and/or log the content of |
Coverage decreased (-0.3%) to 40.398% when pulling 0a598daeaac2e5289b4da61176d697550a3cd53a on aledbf:deny into 5186e93 on kubernetes:master. |
5aca8b6
to
4d3ae91
Compare
Coverage decreased (-0.004%) to 40.729% when pulling 4d3ae91b4d90b8016f848d0e1b33e7d415f2b4c3 on aledbf:deny into 5186e93 on kubernetes:master. |
Coverage increased (+0.6%) to 41.285% when pulling 1102cbd4378ac282bede827f97cb502b9271442d on aledbf:deny into 5186e93 on kubernetes:master. |
Coverage increased (+0.6%) to 41.35% when pulling 854af9eaa98484978c6423c68c872c68168d2f87 on aledbf:deny into 5186e93 on kubernetes:master. |
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 this is a better model for annotation parsing.
My previous comment about error code still applies and I left a few more comments. I'll do another pass once both my comments and the 4xx vs 5xx bit are addressed.
) | ||
|
||
func init() { | ||
// TODO: check permissions required | ||
os.MkdirAll(DefAuthDirectory, 0655) | ||
os.MkdirAll(authDirectory, 0655) |
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.
Maybe we should move this to part of either NewParser
or Parse
and the authDirectory
as an argument to NewParser
?
Right now I think the unit test will run this init block and create /etc/ingress...
on my machine before the test gets a chance to override it.
And init blocks that can be avoided probably should be.
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.
And init blocks that can be avoided probably should be.
Right. I will try to remove the init func.
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.
done
@@ -65,40 +56,49 @@ type BasicDigest struct { | |||
Secured bool `json:"secured"` | |||
} | |||
|
|||
// ParseAnnotations parses the annotations contained in the ingress | |||
type auth struct { | |||
fn func(string) (*api.Secret, error) |
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.
nit: this can definitely be named better.
While we're refactoring though, this could also be an interface and I think that would be a bit more idiomatic.
e.g. SecretResolver { GetSecret(string) ...
And then cfg
could just fulfil that interface and cfg
could directly be passed in.
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.
done
@@ -39,27 +39,36 @@ type SSLCert struct { | |||
PemSHA string `json:"pemSha"` | |||
} | |||
|
|||
type authTLS struct { | |||
fn func(secret string) (*SSLCert, error) |
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.
same comment above about interfaces
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.
done
} | ||
|
||
if str == "" { | ||
return &SSLCert{}, fmt.Errorf("an empty string is not a valid secret name") | ||
return nil, ing_errors.LocationDenied{ |
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.
for consistency, NewLocationDenied
here, or use this sorta constructor everywhere and delete the New
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.
done
} | ||
|
||
_, _, err = k8s.ParseNameNS(str) | ||
if err != nil { | ||
return &SSLCert{}, err | ||
return nil, ing_errors.LocationDenied{ |
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.
same for this err
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.
done
|
||
func (e *annotationExtractor) Extract(ing *extensions.Ingress) map[string]interface{} { | ||
anns := make(map[string]interface{}, 0) | ||
for name, fn := range e.annotations { |
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.
fn
isn't a func
, so this naming is confusing.
Maybe name, annotationParser
?
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.
ok
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.
done
} | ||
err := mergo.Map(loc, anns) | ||
if err != nil { | ||
glog.V(2).Infof("unexpected error merging extracted annotations in location type: %v", err) |
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.
Should this be a Warn
or Error
? When would this happen?
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.
in theory never :)
I will switch this to default level and Error
a882646
to
5f6a472
Compare
Coverage increased (+0.6%) to 41.858% when pulling 5f6a472b9ce5336a8ccb9a4321e46b7cc5909ba0 on aledbf:deny into b2d084a on kubernetes:master. |
With the new errors I changed the code to always print the errors. If the error is related to missing annotations (not an error really) that appears only in V(5).
Error code changed to 503 |
Coverage increased (+0.8%) to 42.069% when pulling 24d61bda0d010e4b3e789b3d81cc347ff8188b9a on aledbf:deny into e58f510 on kubernetes:master. |
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.
Mostly LGTM.
Would have been nice if the review comments were addressed in a new commit on top, not squashed in immediately.
@@ -69,6 +70,12 @@ func ReadConfig(conf *api.ConfigMap) config.Configuration { | |||
to.SkipAccessLogURLs = skipUrls | |||
to.WhitelistSourceRange = whitelist | |||
|
|||
h, err := dns.GetSystemNameServers() |
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 change seems like it should be a separate PR; it doesn't seem related to the rest of this.
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.
Right. Removed.
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.
Moved to PR #123
func isLocationAllowed(input interface{}) bool { | ||
loc, ok := input.(*ingress.Location) | ||
if !ok { | ||
return false |
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.
log an error too, this shouldn't ever happen
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.
done
// AuthCertificate has a method that searchs for a secret | ||
// that contains a SSL certificate. | ||
// The secret must contain 3 keys named: | ||
type AuthCertificate interface { |
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.
Should this also be in resolver
for consistency (resolver.AuthCertificate
to match resolver.Secret
)?
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.
It's already there :( I'm not sure how to remove the cycle error that this introduces.
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 easiest thing is probably to move the type up into resolver as well.
Something like this: euank@608cf8e
I think that's cleaner than the current interface duplication.
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.
done
@@ -93,3 +96,16 @@ func IsValidClass(ing *extensions.Ingress, class string) bool { | |||
|
|||
return cc == class | |||
} | |||
|
|||
const denied = "Denied" |
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.
Export and re-use it as a key in the other places too
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.
done
Sorry about that. I always be told to squash the commits. |
Squash before merge, definitely, but it's often nicer to have review comments separate up until before merge. |
Coverage increased (+1.2%) to 42.38% when pulling f45d5c65ff0e21f2a8d6797886dd823a1a8deff5 on aledbf:deny into f90e9ee on kubernetes:master. |
Coverage increased (+1.2%) to 42.38% when pulling f45d5c65ff0e21f2a8d6797886dd823a1a8deff5 on aledbf:deny into f90e9ee on kubernetes:master. |
val, err := annotationParser.Parse(ing) | ||
glog.V(5).Infof("annotation %v in Ingress %v/%v: %v", name, ing.GetNamespace(), ing.GetName(), val) | ||
if err != nil { | ||
_, de := anns["Denied"] |
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.
Would be nice to use the const here too. It makes it easier to find where that key's set programmatically.
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.
nit, 'de' -> 'alreadyDenied' would be more readable imo
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.
done
} | ||
|
||
return fn(str) | ||
return a.certResolver.GetAuthCertificate(str) |
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 it makes sense to wrap the error returned from this in a location denied.
This errors if the referenced cert can't be resolved, and that sounds like excellent grounds to deny.
glog.Errorf("error reading %v annotation in Ingress %v/%v: %v", name, ing.GetNamespace(), ing.GetName(), err) | ||
continue | ||
} | ||
glog.V(5).Infof("error reading %v annotation in Ingress %v/%v: %v", name, ing.GetNamespace(), ing.GetName(), err) |
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 GetAuthCertificate
thing above I think is an argument for changing the logic about setting the "Denied" key to default to true for any error, and only be skipped for a subset of recognized errors (e.g. AnnotationMissing).
For now we could just set denied here and refactor further if there are more errors that need to be treated differently.
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.
You are right. Without this change we can end with the same error we have in 0.8.3.
Key "Denied" changes for any error now.
Review pass done, apologies for the delay on it. If you want to just handle the |
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 (with appropriate squashing ofc)
@euank thanks for the review! |
Sync upstream
fixes #16
fixes #108