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

Kubernetes security header annotations #2460

Merged
merged 3 commits into from Nov 28, 2017

Conversation

dtomcej
Copy link
Contributor

@dtomcej dtomcej commented Nov 24, 2017

This PR implements the secure headers middleware from kubernetes annotations. This PR follows up #2334 and #2146.

@ldez
Copy link
Member

ldez commented Nov 26, 2017

@dtomcej to fix the "gen pb" could you rebase your branch?

Copy link
Contributor

@timoreimann timoreimann left a comment

Choose a reason for hiding this comment

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

I know the PR isn't ready yet, but I thought it could be worthwhile to give some early feedback, especially if we want this to still make it into 1.5. Hope you don't mind!

func getSliceAnnotation(meta v1.ObjectMeta, name string) []string {
value := []string{}
if annotation := meta.Annotations[name]; annotation != "" {
for _, subannotation := range strings.Split(annotation, ",") {
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, I'm not sure if the name subannotation is ideal. To me, it gives a fault sense of an annotation (that is, a map) inside an existing annotation. IIRC correctly, however, it's just a list of values.

How about calling the variable value then (and adjust the log message below accordingly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure.

Subannotation was a carry over from the docker where labels get clumped together.

if annotation := meta.Annotations[name]; annotation != "" {
for _, subannotation := range strings.Split(annotation, ",") {
if len(subannotation) == 0 {
log.Warnf("Could not load annotation %v, skipping", subannotation)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the message should be more specific and about the fact we couldn't find any values for a known annotation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

}
}
if len(value) == 0 {
log.Warnf("Could not load %v annotation", name)
Copy link
Contributor

Choose a reason for hiding this comment

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

The skipping part is missing here.

}
if len(value) == 0 {
log.Warnf("Could not load %v annotation", name)
return nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have to be conscious about security-critical cases where missing header value should lead to the whole Ingress being skipped? I'm thinking of the equivalent of missing basic auth credentials that shouldn't lead to a frontend being accessible without authentication.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nothing here really prevents code from loading, just appends or changes headers.

return nil
}
return value
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The file is starting to get cluttered. How about moving those little helpers into a helpers.go file?

Copy link
Member

Choose a reason for hiding this comment

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

please no helpers/utils.go file. In test ok but not in the prod code

Copy link
Contributor

Choose a reason for hiding this comment

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

No disagreement in code reviews without an alternative suggestion, they say.

What do you suggest instead?

Copy link
Member

Choose a reason for hiding this comment

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

yes, annotations_parser.go or annotations.go by example.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do! 👍

value := []string{}
if annotation := meta.Annotations[name]; annotation != "" {
for _, subannotation := range strings.Split(annotation, ",") {
if len(subannotation) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not entirely sure, but doesn't Split on an empty string yield the empty string, i.e., ""? That would still be non-zero in terms of the length.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wow. Did not know that. Will update accordingly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahhh so in this case, its to catch empty sub-elements (such as x,y,,z). The empty test is on the line above :)

@dtomcej dtomcej force-pushed the kubernetes-secure-annotations branch from 9a5d445 to cb9c79c Compare November 27, 2017 15:37
@dtomcej
Copy link
Contributor Author

dtomcej commented Nov 27, 2017

@ldez Rebased!

@dtomcej dtomcej force-pushed the kubernetes-secure-annotations branch from 09f35c3 to a0315a9 Compare November 27, 2017 16:11
[frontends."{{$frontendName}}".headers]
SSLRedirect = {{$frontend.Headers.SSLRedirect}}
SSLTemporaryRedirect = {{$frontend.Headers.SSLTemporaryRedirect}}
SSLHost = "{{$frontend.Headers.SSLHost}}""
Copy link
Member

Choose a reason for hiding this comment

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

small typo: double double quote 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Eagle eyes

@dtomcej dtomcej force-pushed the kubernetes-secure-annotations branch 2 times, most recently from dea3558 to ff9947d Compare November 27, 2017 18:43
@dtomcej dtomcej closed this Nov 27, 2017
@dtomcej dtomcej reopened this Nov 27, 2017
@ldez ldez force-pushed the kubernetes-secure-annotations branch from 7f67d54 to 1431e26 Compare November 28, 2017 00:19
@@ -53,7 +73,7 @@ type Provider struct {
lastConfiguration safe.Safe
}

func (p *Provider) newK8sClient() (Client, error) {
func (p Provider) newK8sClient() (Client, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we really want a copy of Provider when calling newK8sClient now?

Copy link
Member

@ldez ldez Nov 28, 2017

Choose a reason for hiding this comment

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

We don't reload the static configuration (eg we don't recreate the client).

NewInClusterClient(endpoint string) and NewExternalClusterClient(endpoint, token, caFilePath string) use string, a pointer as receiver don't change anything.

The use of a pointer as a receiver must be reserved only when a method changes the state of the receiver. (use a pointer as a receiver produce an escape to heap)

Maybe I have miss something?

Copy link
Contributor

Choose a reason for hiding this comment

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

Late to the game, sorry.

The problem with receivers in Go is that they conflate two aspects: Mutability and performance / copy overhead. The Go Code Review Comments have a paragraph on the subject, but eventually suggest to leans towards pointer receivers, especially when the involved receiver is a non-trivial struct. I certainly think that Provider is rather complex (especially since it embeds another BaseProvider), so a pointer receiver would have been in order for me.

Copy link
Member

@ldez ldez left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@juliens juliens left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@mmatur mmatur left a comment

Choose a reason for hiding this comment

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

LGTM 👏

dtomcej and others added 3 commits November 28, 2017 11:04
add anno list

add remove forcessl

add k8s headers

change error to warn log

change empty maps to nil

woops durp

quote strings

fix autogen

update value/logging

lol double quote

move parsing

template out empty maps

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

Successfully merging this pull request may close these issues.

None yet

6 participants