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

Move audit filter before authn to log those failures as well #14535

Closed
wants to merge 2 commits into from

Conversation

soltysh
Copy link
Member

@soltysh soltysh commented Jun 8, 2017

@mfojtik @smarterclayton this change is logging authn failures in audit, this is the sample output:

AUDIT: id="b6d649e5-452e-456f-8af2-7f3f8d56f24a" ip="127.0.0.1" method="GET" user="<none>" groups="<none>" as="<self>" asgroups="<lookup>" namespace="<none>" uri="/oauth/authorize?response_type=token&client_id=openshift-challenging-client"                                                                                                                                                                                                                                        
AUDIT: id="b6d649e5-452e-456f-8af2-7f3f8d56f24a" response="401"

@sttts @liggitt @deads2k fyi

@soltysh
Copy link
Member Author

soltysh commented Jun 8, 2017

@mpbarrett fyi

@smarterclayton
Copy link
Contributor

And it even looks easy to backport... :)

@smarterclayton
Copy link
Contributor

So if we do this are we loosing the info from the user that is loaded during authentication?

@sttts
Copy link
Contributor

sttts commented Jun 9, 2017

So if we do this are we loosing the info from the user that is loaded during authentication?

Looks like.

I wonder whether we can't have both: put a fallback filter before authn, but keep the full-featured one where it is. If the later does not trigger (we can use a context value to know that), the fallback one will log the authn error.

We haven't thought about this in advanced auditing either, but there we carry around the audit event in the context already.

@smarterclayton
Copy link
Contributor

smarterclayton commented Jun 9, 2017 via email

@soltysh
Copy link
Member Author

soltysh commented Jun 14, 2017

@sttts @smarterclayton I've pushed current state with proposed changes from you guys, but it looks like I'm currently getting a bit more requests than I expected. Checkout this output: https://paste.fedoraproject.org/paste/ZZwM0dB7YQLypbXVqq5qiw and search for lines with user=<???> which are coming from the new filter, should limit the output to only authorization or dig why the original audit did not caught them?

@soltysh
Copy link
Member Author

soltysh commented Jun 14, 2017

Nvmd wrt to those double lines, it looks like my flag isn't working as I expected it to be :/

@soltysh
Copy link
Member Author

soltysh commented Jun 14, 2017

Of course I forgot to update the context mapper with new context data, updated, now it should be good. I still need to update the user to be reasonable.

apirequest "k8s.io/apiserver/pkg/endpoints/request"
)

const AUDIT_TRIGGERED = "audittriggered"
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 capital case constants?

func (a *auditResponseWriter) WriteHeader(code int) {
ctx, ok := a.requestContextMapper.Get(a.req)
if !ok {
glog.Errorf("Unable to get RequestContextMapper and read context data!")
Copy link
Contributor

Choose a reason for hiding this comment

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

worth a panic

Copy link
Member Author

Choose a reason for hiding this comment

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

we're returning 500 in the original audit, I'll do the same here.


var _ http.ResponseWriter = &auditResponseWriter{}

type auditResponseWriter struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

a good comment would be nice. It doesn't sound like this is just the fallback for the upstream audit handler. Maybe call it authFallbackAuditResponseWriter?


// withAuditWrapper decorates a http.Handler with audit logging information for all the
// requests coming to the server. If out is nil, no decoration takes place.
func withAuditWrapper(handler http.Handler, requestContextMapper apirequest.RequestContextMapper, out io.Writer) http.Handler {
Copy link
Contributor

Choose a reason for hiding this comment

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

in fact there is no relation between WithAudit and this, isn't there? Would prefer WithAuditTriggeredMarker or something like that and an additional WithAudit call in the handler chain builder


// withAuthnAudit decorates a http.Handler with audit logging ONLY information
// related to failed Authn requests.
func withAuthnAudit(handler http.Handler, requestContextMapper apirequest.RequestContextMapper, out io.Writer) http.Handler {
Copy link
Contributor

Choose a reason for hiding this comment

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

WithAuthFallbackAudit

@soltysh
Copy link
Member Author

soltysh commented Jun 14, 2017

I've addressed @sttts comments. The remaining piece, I'm currently working on, is adding information about auth methods used for authentication.

user, ok, err := authenticator.AuthenticateRequest(req)
if err != nil || !ok {
ctx = apirequest.WithValue(ctx, AuditAuthnUser, user)
ctx = apirequest.WithValue(ctx, AuditAuthnError, err)
Copy link
Member Author

Choose a reason for hiding this comment

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

@smarterclayton I've tried this approach to get the user and error and return that in the fallback audit logs, but it doesn't work :/ @sttts proposed we change AuthenticateRequest signature by extending its return type with additional []AuthenticationResult which will provide the information about user and method, with possibility to extend that in the future. We'd upstream this into 1.8, obviously. The only problem is that it might require a bit more work, and we're just closing 3.6. The other approach is to duplicate the logic responsible for getting user information in the fallback audit, and for token requests we'd just say it's that. wdyt?

Copy link
Member Author

Choose a reason for hiding this comment

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

@mfojtik @pweil- fyi, since this is one of must have for 3.6

@soltysh
Copy link
Member Author

soltysh commented Jun 14, 2017

[test]

@smarterclayton
Copy link
Contributor

smarterclayton commented Jun 14, 2017 via email

@soltysh
Copy link
Member Author

soltysh commented Jun 16, 2017

Here's the current sample output:

AUDIT: id="abfadeb6-f52c-4e67-9e07-726e35992a89" ip="127.0.0.1" method="GET" user="mysillyusername" uri="/oauth/authorize?response_type=token&client_id=openshift-challenging-client"
AUDIT: id="abfadeb6-f52c-4e67-9e07-726e35992a89" response="401"
AUDIT: id="5db6d679-9820-4100-890c-4c9b297e7eec" ip="127.0.0.1" method="GET" user="<bearer>" uri="/api/v1/namespaces/test/pods"
AUDIT: id="5db6d679-9820-4100-890c-4c9b297e7eec" response="401"


// getUsername returns username or information on the authn method being used.
func getUsername(req *http.Request) string {
auth := strings.TrimSpace(req.Header.Get("Authorization"))
Copy link
Member Author

Choose a reason for hiding this comment

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

@liggitt || @enj mind double checking if I'm missing something here?

@mfojtik
Copy link
Contributor

mfojtik commented Jun 16, 2017

@soltysh love it.

}

// other tokens
token := strings.TrimSpace(req.URL.Query().Get("access_token"))
Copy link
Contributor

Choose a reason for hiding this comment

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

logging URLs before the auth filter can expose the query params

}

// check basic auth
const basicScheme string = "Basic "
Copy link
Contributor

Choose a reason for hiding this comment

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

we don't support basic auth to our API, what is making use of this?

Copy link
Member Author

Choose a reason for hiding this comment

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

Wasn't sure if we support or not, but I found the code in origin, so I've implemented it also here.

if len(parts) > 1 && strings.ToLower(parts[0]) == "bearer" {
token := parts[1]
// Empty bearer tokens aren't valid
if len(token) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

doing this to detect Authorization: Bearer doesn't seem very useful

Copy link
Contributor

Choose a reason for hiding this comment

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

it also draws a false distinction between empty bearer tokens and present but invalid bearer tokens

Copy link
Member Author

Choose a reason for hiding this comment

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

I've tried with wrong and empty Bearer token and haven't seen any difference, I'll leave just the bearer check and will go with that.

}

// getUsername returns username or information on the authn method being used.
func getUsername(req *http.Request) string {
Copy link
Contributor

Choose a reason for hiding this comment

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

this doesn't account for client cert auth

return
}
id := uuid.NewRandom().String()
line := fmt.Sprintf("%s AUDIT: id=%q ip=%q method=%q user=%q uri=%q\n",
Copy link
Contributor

Choose a reason for hiding this comment

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

presenting the results of getUsername() as user=... seems wrong... it can attribute a request to a specific user pre-authentication, when it should be clearer that this is information the user presented that has not been verified in any way

Copy link
Member Author

Choose a reason for hiding this comment

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

What else are you proposing?

}

// cert authn
if req.TLS != nil && len(req.TLS.PeerCertificates) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

this will be confused by an auth proxy that presents a client cert and communicates user info in headers

Copy link
Member Author

Choose a reason for hiding this comment

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

How can I fix this?

@openshift-bot
Copy link
Contributor

continuous-integration/openshift-jenkins/test FAILURE (https://ci.openshift.redhat.com/jenkins/job/test_pull_request_origin/2314/) (Base Commit: 4aa3720) (PR Branch Commit: 33007d2)

@openshift-merge-robot openshift-merge-robot added needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jul 24, 2017
@openshift-merge-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: soltysh
We suggest the following additional approver: deads2k

Assign the PR to them by writing /assign @deads2k in a comment when ready.

No associated issue. Update pull-request body to add a reference to an issue, or get approval with /approve no-issue

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these OWNERS Files:

You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@openshift-merge-robot openshift-merge-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 28, 2017
@openshift-merge-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: soltysh
We suggest the following additional approver: deads2k

Assign the PR to them by writing /assign @deads2k in a comment when ready.

No associated issue. Update pull-request body to add a reference to an issue, or get approval with /approve no-issue

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these OWNERS Files:

You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@openshift-merge-robot openshift-merge-robot removed the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 28, 2017
@openshift-merge-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: soltysh
We suggest the following additional approver: deads2k

Assign the PR to them by writing /assign @deads2k in a comment when ready.

No associated issue. Update pull-request body to add a reference to an issue, or get approval with /approve no-issue

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these OWNERS Files:

You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@soltysh soltysh force-pushed the authn_audit branch 2 times, most recently from 7442b22 to b9872bc Compare August 14, 2017 21:58
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Aug 14, 2017
@soltysh
Copy link
Member Author

soltysh commented Aug 14, 2017

@sttts ptal the audit bits, it's mostly copy&paste of the upstream handler. I'm wondering if we should just make it a public method instead of copying it here
@liggitt for the getUsername part, since you've had objections there. Is it sufficient or we need more usecases to cover.

@soltysh
Copy link
Member Author

soltysh commented Aug 14, 2017

}

// if there already exists an audit event in the context we don't need to do anything
if ae := request.AuditEventFrom(ctx); ae != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

that's a lot of copied code. Don't like this. What are our options?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, me neither. I was thinking about making this whole thing a helper function in audit upstream, wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

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

What was the reason to not do the same as this PR in upstream?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure, I think I can give it a try.

Copy link
Contributor

Choose a reason for hiding this comment

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

If we get rid of maintaining our fork, go for it.

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Aug 17, 2017
@soltysh
Copy link
Member Author

soltysh commented Aug 23, 2017

This is waiting for upstream PR kubernetes/kubernetes#51119

@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Sep 1, 2017
@openshift-merge-robot
Copy link
Contributor

@soltysh PR needs rebase

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Sep 2, 2017
@soltysh
Copy link
Member Author

soltysh commented Sep 6, 2017

This is waiting for #16106 and #16110 to land since they are changing authn and authz bits.

@soltysh
Copy link
Member Author

soltysh commented Sep 18, 2017

I'm closing this in favor of #16128 where I'll include the changes from this PR.

@soltysh soltysh closed this Sep 18, 2017
@soltysh soltysh deleted the authn_audit branch September 18, 2017 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants