Skip to content

Commit

Permalink
authentication/login-logout: initial enhancement
Browse files Browse the repository at this point in the history
Co-authored-by: Krzysztof Ostrowski <kostrows@redhat.com>
  • Loading branch information
s-urbaniak and ibihim committed Nov 5, 2021
1 parent 98f33c5 commit 8ba51bb
Showing 1 changed file with 308 additions and 0 deletions.
308 changes: 308 additions & 0 deletions enhancements/authentication/login-logout-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
---
title: Login Logout Auditing
authors:
- "@s-urbaniak"
reviewers:
- "@mfojtik"
- "@deads2k"
- "@stlaz"
- "@sttts"
approvers:
- "@Anandnatraj"
- "@oscardoe"
creation-date: 2021-09-10
last-updated: 2021-09-10
status: implementable
see-also:
- "/enhancements/kube-apiserver/audit-policy.md"
---

# Logging login, login failure and logout events

## Release Signoff Checklist

- [ ] Enhancement is `implementable`
- [ ] Design details are appropriately documented from clear requirements
- [ ] Test plan is defined
- [ ] Operational readiness criteria is defined
- [ ] Graduation criteria for dev preview, tech preview, GA
- [ ] User-facing documentation is created in [openshift-docs](https://github.com/openshift/openshift-docs/)

## Summary

This enhancement describes capturing login, login failure, and logout events in the OpenShift authentication subsystems.

Currently, login and logout events can only be derived from inspecting audit logs. These include creation or deletion of `oauthaccesstokens` resources as described in the API server [Audit Policy Configuration](https://github.com/openshift/enhancements/blob/master/enhancements/kube-apiserver/audit-policy.md#logging-of-token-with-secure-oauth-storage).

This approach has a couple of drawbacks:
1. Login events are captured via creation events of `oauthaccesstokens` in audit logs. This includes successful login events only, but not all login failures. Currently the only login failure that can be deduced from the audit logs is the inability of exchanging the oauthauthorizetoken for an oauthaccesstoken as we log creation of both of these objects.
2. Logout events are captured via deletion events of `oauthaccesstokens` in audit logs. Here only references to the sha256 based access token are present in audit logs, but no additional information about the underlying username who logged out.

## Motivation

### Goals

1. Add capabilities in oauth-server to create audit-like logs. Gate fine grained audit log events via a simple profile configuration mechanism.
2. Extend oauth-server to capture login and login failure events.
3. Extend oauth-apiserver to add user information when deleting `oauthaccesstoken` objects.
4. Extend must-gather/gather_audit_logs to fetch oauth-server audit logs.

### Non-Goals

1. Hook into the existing API server [policy configuration](https://github.com/openshift/enhancements/blob/master/enhancements/kube-apiserver/audit-policy.md).
2. Provide a fully featured audit subsystem in oauth-server compliant with API server policy framework.
3. Rate limiting of logging login/logout events.

## Proposal

We propose to add an `audit` struct to `oauth.config.openshift.io/v1` with a `profile` field which configures audit logging granularity.

```go
// OAuthSpec contains desired cluster auth configuration
type OAuthSpec struct {
// identityProviders is an ordered list of ways for a user to identify themselves.
// When this list is empty, no identities are provisioned for users.
// +optional
// +listType=atomic
IdentityProviders []IdentityProvider `json:"identityProviders,omitempty"`

// tokenConfig contains options for authorization and access tokens
TokenConfig TokenConfig `json:"tokenConfig"`

// templates allow you to customize pages like the login page.
// +optional
Templates OAuthTemplates `json:"templates"`
// audit specifies what should be audited in the context of OAuthServer.
// +optional
// +kubebuilder:default:={"profile":"WriteLoginEvents"}
Audit OAuthAudit `json:"audit"`
}

// OAuthAudit specifies the Audit profile in use.
type OAuthAudit struct {
// profile is a simple drop in profile type that can be turned off by
// setting it to "None" or it can be turned on by setting it to
// "WriteLoginEvents".
// +kubebuilder:default:="WriteLoginEvents"
Profile OAuthAuditProfileType `json:"profile,omitempty"`
}

// OAuthAuditProfileType defines a simple audit profile, which can turn OAuth
// authentication audit logging on or off.
// +kubebuilder:validation:Enum=None;WriteLoginEvents
type OAuthAuditProfileType string

const (
// "None" disables audit logs.
OAuthNoneAuditProfileType AuditProfileType = "None"

// "WriteLoginEvents" logs login and login failure events.
// This is the default.
OAuthWriteLoginEventsProfileType AuditProfileType = "WriteLoginEvents"
)
```

### User Stories

### As an administrator I want to inspect successful login and login failure attempts

Use `oc adm must-gather -- /usr/bin/gather_audit_logs` and inspect oauth-server audit logs.

### As an administrator I want to inspect logout events and the deleted user

Use `oc adm must-gather -- /usr/bin/gather_audit_logs` and inspect apiserver audit logs for deleted `oauthaccesstoken` resources.
Audit log entries include the deleted user.

### As an administrator I want to inspect the source IPs of the client triggering an authentication event

### Risks and Mitigations

There are no big risks. As with logging, we could always log something that we shouldn't and violate compliance.

The mitigation for the customer would be to turn audit logging of and for the development team to fix the logging and mask sensitive data.

## Design Details

### Successful Login and Login failure events

To create successful login and login failure audit events differ slightly depending on the underlying identity provider. There are the following cases to consider:

1. **Password-based identity providers**

All password-based identity providers are using a [central location](https://github.com/openshift/oauth-server/blob/690499e76a0b242adb5ccc73f23cccc8a50b8788/pkg/server/login/login.go#L173) where login events are handled. Both login success and failure events will be emitted here.

2. **External OAuth identity providers**

For login events external OAuth providers must invoke oauth-server callback handler to finalize authorization using [code grant flow](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1).

Login success will be emitted upon successful code exchange between the oauth-server and the OIDC IdP in the [central OAuth callback handler](https://github.com/openshift/oauth-server/blob/822478f88514a80f053d9f65cd689d981b6ea4fd/pkg/oauth/external/handler.go#L149-L157).

Login failure however cannot be easily detected as there is no guarantee that external oauth providers will invoke callback in the case of a login failure. Hence, only best-effort login failure events can be emitted, if the external OAuth provider provides an `error` response in the [central `HandleRequest` handler](https://github.com/openshift/oauth-server/blob/513a8bb5b6cbd5e8faacbed523eb861aa29a674b/vendor/github.com/RangelReale/osincli/authorize.go#L84).

3. **External OAuth identity providers used as challengers**

External oauth identity providers used as challengers use a [central location](https://github.com/openshift/oauth-server/blob/822478f88514a80f053d9f65cd689d981b6ea4fd/pkg/oauth/external/handler.go#L118) where login and login failures audit events will be emitted.

4. **Request Header identity provider**

For this case an established trust to the external login proxy exists via means of client certificate trust. This implies that all authentication requests, are assumed to have passed successful the authentication in the external 3rd party proxy.

Thus, successful Login events can easily be constructed by creating audit events in the [central request authentication method](https://github.com/openshift/oauth-server/blob/4e63f0f350f28171edc4ae2553c7b852e65efbc6/pkg/authenticator/request/headerrequest/requestheader.go#L34).

Login failure events, however never cause a request header authentication request to be generated in the 3rd party proxy, thus those events cannot be detected in oauth-server for this use case.

### Logout events

#### oauth-server

Logout events are not visible to oauth-server as the infrastructure in OpenShift does not have a central logout handler mechanism. Instead we have to rely on audit events against deletion of `oauthaccesstoken` resources.

#### oauth-apiserver

The deletion of `oauthaccesstoken` is logged within the `oauth-apiserver`. Currently, only a `Status` object is created in an deletion event entry of the following form:

```json
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
...
"verb": "delete",
...
"responseObject": {
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Success",
"details": {
"name": "sha256~sometoken",
"group": "oauth.openshift.io",
"kind": "oauthaccesstokens",
"uid": "444845f0-1348-4ab1-95be-d0644a6bd11c"
}
},
...
}
```

To log the complete object we have to set `ReturnDeletedObject: true` on the oauth-apiserver REST Store: https://github.com/openshift/oauth-apiserver/blob/6e0f92194d5a25728c826fefb2d99c5e88ebb5e5/pkg/oauth/apiserver/registry/oauthaccesstoken/etcd/etcd.go#L30-L46.

This will allow to introspect the deleted user:

```json
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
...
"verb": "delete",
...
"responseObject": {
"kind": "OAuthAccessToken",
"apiVersion": "oauth.openshift.io/v1",
"metadata": {
...
"userName": "exampleuser",
},
"userUID": "123",
"authorizeToken": "sha256~sometoken"
},
...
}
```

### Event construction

In all cases above an [Info](https://github.com/openshift/oauth-server/blob/961295a3151da3fff9daa5ea0ab8c0bf92a7d7e6/vendor/k8s.io/apiserver/pkg/authentication/user/user.go#L20) entity is available with user information which can be used to fill audit event data.

### Integration in must-gather

The existing `oc adm must-gather -- /usr/bin/gather_audit_logs` tool will also fetch oauth-server audit logs.

### DoS mitigation

To prevent flooding audit event logs we rely on the existing default apiserver handler chain which is used to serve oauth-server http resources.

Currently, the default configuration of apiserver's `MaxRequestsInFlight` (i.e. GET requests) and `MaxMutatingRequestsInFlight` (i.e. POST requests) are used as part of the [default configuration](https://github.com/openshift/oauth-server/blob/961295a3151da3fff9daa5ea0ab8c0bf92a7d7e6/vendor/k8s.io/apiserver/pkg/server/config.go#L330-L331) to protect against audit event flooding.

### Graduation Criteria

This feature is planned for OpenShift 4.10.

#### Dev Preview -> Tech Preview

- Audit logging should work.

#### Tech Preview -> GA

- No sensitive data is logged.
- Verbosity should be acceptable.

#### Removing a deprecated feature

N/A

### Upgrade / Downgrade Strategy

As we are introducing a new property with default values, there are not expected risks for upgrading.

Downgrading would not cause any data loss or inconsistencies as the property is a simple feature flag to toggle audit logging.

### Version Skew Strategy

All components will be developed with the concern of version skew in mind. So they will handle the missing of the `Audit` property.

### Test Plan

Ideally we test our feature with:

- unit tests,
- e2e tests in origin and
- tests at must-gather.

#### E2E testing steps

In order to test the audit logging as mentioned in the porposal:

**Verify audit logging**

1. Create a cluster with OpenShift installed on it.
2. Verify that the version deployed contains this enhancement.
3. Verify that the custom resource `OAuth` exists and contains the properties:

```yaml
audit:
profile: WriteLoginEvents
```
4. Create Login failures, Login and Logout events.
5. Execute `oc adm must-gather`.
6. Verify that the gathered logs contain logs from `oauth-server`.
7. Verify that the events caused in `4.` are logged.

**Verify audit logging can be turned off**

1. Create a cluster with OpenShift installed on it.
2. Verify that the version deployed contains this enhancement.
3. Verify that the custom resource `OAuth` exists and contains the properties:

```yaml
audit:
profile: WriteLoginEvents
```
4. Edit the yaml and replace `WriteLoginEvents` with `None`.
5. Create Login failures, Login and Logout events.
6. Execute `oc adm must-gather`.
7. Verify that there is no audit logging from the `oaut-server`.

## Implementation History

N/A

## Drawbacks

We create more log entries, which increases the space that the logs will occupy.

## Alternatives

The alternative is to keep on relying on `oauthaccesstoken` audit events with the aforementioned drawbacks.

0 comments on commit 8ba51bb

Please sign in to comment.