-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Draft design for single-use-token authenticator
- Loading branch information
Showing
8 changed files
with
566 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
277 changes: 277 additions & 0 deletions
277
design/authenticators/authn_sut/authn_sut_solution_design.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,277 @@ | ||
# Single Use Token (SUT) Authenticator | ||
|
||
## Overview/Introduction | ||
|
||
The Single Use Token (SUT) Authenticator is a new authenticator for Conjur that | ||
will allow users to authenticate to Conjur using a single-use token. A user will | ||
be able to generate a single use token by providing their username and password | ||
to a new API endpoint. The user will then be able to use the token to | ||
authenticate to Conjur. | ||
|
||
## Summary of Existing Functionality | ||
|
||
There is currently no way to create a single-use token for authenticating to | ||
Conjur. | ||
|
||
## Requirements | ||
|
||
The driver behind this effort is to enable integration between Conjur UI and | ||
PSM. That integration will require a mechanism for generating a single-use token | ||
that can be used to authenticate to Conjur. The requirements for this effort are | ||
as follows: | ||
|
||
### Feature Spec for Conjur UI-PSM Integration (CNJR-2392) | ||
|
||
> Privileged Session Manager (PSM) enables users to log on to remote | ||
> machines/applications securely through a proxy machine facilitating | ||
> streamlined and native workflows for the IT admins. Conjur is now going to | ||
> integrate with PSM providing integrity across Cyberark products and easy | ||
> access to the Conjur UI via PSM. | ||
> | ||
> In order for PSM to connect to the Conjur UI, a new API(s) would be provided | ||
> that PSM could call to establish the UI session and login the user directly | ||
> into the main UI dashboard, without showing the initial login screen. More | ||
> details will be added in the solution design (TBD). | ||
> | ||
> The overall UX will remain the same where users will continue to use the | ||
> existing workflow of logging onto the PVWA, clicking connect on a defined | ||
> Conjur instance 1 and connecting through PSM straight into the Conjur UI | ||
> console. | ||
The SUT authenticator will be the mechanism used to authenticate the user to | ||
Conjur when they click "Connect" on a Conjur instance in PVWA. PSM will generate | ||
a SUT for the user using their stored username and password or API key. PSM will | ||
then pass the SUT to the Conjur UI via a URL parameter. The Conjur UI will use | ||
the SUT to authenticate the user to Conjur and start a session. | ||
|
||
## Assumptions and Prerequisites | ||
|
||
Assumptions: Defining the assumptions being made in preparing this Solution | ||
Design. Detailing why these assumptions are valid and/or acceptable. | ||
Prerequisites: Do we need additional tooling to develop this feature? Do we need | ||
additional tooling to test this feature in our pipeline? What needs to be in | ||
place to build this feature? | ||
|
||
## Out-of-scope | ||
|
||
- SUTs will not be able to be used to authenticate to Conjur via the CLI | ||
- SUTs are intended to be used in automated processes. The CLI is intended to | ||
be used by humans (developers, operators, etc.) | ||
- There are many possible use cases for SUTs. This effort will focus on the | ||
basic use case necessary for Conjur UI-PSM integration. Additional use cases | ||
may be considered in the future. | ||
- The PSM integration itself will not be part of this effort. This effort will | ||
only focus on the SUT authenticator and the API endpoint for generating SUTs. | ||
The PSM team will implement the PSM integration in a separate effort in the | ||
PSM codebase. | ||
|
||
## Design | ||
|
||
### High-Level Design | ||
|
||
#### Workflows | ||
|
||
##### Basic SUT Workflow | ||
|
||
The following diagram shows the basic workflow for using a SUT to authenticate | ||
to Conjur. The first step is to call the | ||
`GET /authn-sut/<authenticator-name>/<account>/login` endpoint with the user's | ||
credentials to generate a SUT. The SUT is then passed to the | ||
`POST /authn-sut/<authenticator-name>/<account>/authenticate` | ||
endpoint to authenticate the user to Conjur and retrieve a short-lived auth | ||
token. | ||
|
||
![Basic SUT Workflow](./sut.png) | ||
|
||
##### 3rd Party Client Workflow | ||
|
||
The following diagram shows the workflow for using a SUT to authenticate to | ||
Conjur on behalf of a 3rd party client. The first step is to call the | ||
`GET /authn-sut/<authenticator-name>/<account>/login` endpoint with the user's | ||
credentials to generate a SUT. The SUT is then handed off to the 3rd party | ||
client. The 3rd party client then calls the | ||
`POST /authn-sut/<authenticator-name>/<account>/authenticate` | ||
endpoint with the SUT to authenticate the user to Conjur and retrieve a | ||
short-lived auth token. This way the 3rd party client never has access to the | ||
user's credentials. | ||
|
||
![3rd Party Client Workflow](./sut_3rd_party.png) | ||
|
||
##### PSM Integration Workflow | ||
|
||
The following diagram shows the workflow for using a SUT to authenticate to | ||
Conjur via the PSM integration. The first step is to call the | ||
`GET /authn-sut/<authenticator-name>/<account>/login` endpoint with the user's | ||
credentials to generate a SUT. The SUT is then passed to the Conjur UI via a URL | ||
parameter: `GET <conjur-ui-url>/ui/callback?sut=<sut>`. The Conjur UI then calls | ||
the `POST /authn-sut/<authenticator-name>/<account>/authenticate` endpoint with | ||
the SUT to authenticate the user to Conjur and retrieve a short-lived auth | ||
token. The Conjur UI then starts a session for the user. | ||
|
||
![PSM Integration Workflow](./psm.png) | ||
|
||
<!-- TODO: Workflow State Visibility, Log messages, Audit logs --> | ||
|
||
#### Policy | ||
|
||
As with other authenticators, the SUT authenticator will be disabled by default. | ||
It will be enabled by creating an authenticator policy resource in Conjur and | ||
adding it to the list of enabled authenticators in the Conjur configuration, for | ||
example in the `CONJUR_AUTHENTICATORS` environment variable. | ||
|
||
The authenticator webservice must be declared in Conjur policy: | ||
|
||
```yml | ||
- !policy | ||
id: conjur/authn-sut/<authenticator-name> | ||
body: | ||
- !webservice | ||
|
||
- !group clients | ||
|
||
- !permit | ||
role: !group clients | ||
privilege: [ read, authenticate ] | ||
resource: !webservice | ||
``` | ||
and the `clients` group can be used to entitle a user(s) to use the | ||
authenticator: | ||
|
||
```yml | ||
- !grant | ||
role: !group conjur/authn-sut/<authenticator-name>/clients | ||
member: !user <username> | ||
``` | ||
|
||
#### API | ||
|
||
We will need two new API endpoints for the SUT authenticator: | ||
|
||
##### `GET /authn-sut/<authenticator-name>/<account>/login` | ||
|
||
This endpoint will be used to generate a SUT for a user. The user will provide | ||
their username and password (or API key) in the request body. The endpoint will | ||
return a SUT that can be used to authenticate the user to Conjur. | ||
|
||
The format of the URL matches the existing authenticator endpoint for | ||
authn-ldap. | ||
|
||
##### `POST /authn-sut/<authenticator-name>/<account>/authenticate` | ||
|
||
This endpoint will be used to authenticate a user to Conjur using a SUT. The | ||
user will provide the SUT in the request body. The endpoint will return a | ||
short-lived auth token. | ||
|
||
The format of the URL matches the existing authenticator endpoint for | ||
authn-ldap. | ||
|
||
### Low Level Design | ||
|
||
#### Data Model | ||
|
||
The SUT will be a cryptographically secure, random string. It will be generated | ||
by the Conjur server and stored in the database. The SUT will be associated with | ||
the user and expiration time. The SUT will be marked as used once it is utilized | ||
to authenticate the user to Conjur. | ||
|
||
When we store the SUT in the database, we will store a hash of the SUT instead | ||
of the SUT itself. This will prevent an attacker with access to the database | ||
from being able to use the SUTs to authenticate to Conjur. The SUT will be | ||
hashed using a cryptographically secure hash function, such as SHA-256. | ||
When a user presents a SUT to authenticate to Conjur, we will hash the SUT and | ||
compare it to the hash stored in the database. | ||
|
||
##### SUT Format | ||
|
||
We cannot use JWTs for the SUT as we need the ability to revoke the SUT after it | ||
is used, a feature not easily implemented with JWTs. This would make it | ||
impossible to prevent replay attacks. | ||
|
||
##### Open Questions | ||
|
||
- Is it possible to restrict use of the SUT to a specific IP range (like with | ||
hostfactory tokens) or other criteria to limit risk if the SUT is leaked? | ||
- Is it better to actually delete the SUT from the database once it is used or | ||
to just mark it as used? | ||
- Is it better to store a `used_at` timestamp or a boolean `used` flag? | ||
- Should the SUT expiration be configurable (via policy) or should it be a fixed | ||
value? What should the default expiration be? (30 seconds?) | ||
|
||
##### Example Database Table | ||
|
||
| id | role_id | guid_hash | expires_at | used_at | | ||
|----|---------|-----------|------------|---------| | ||
| 1 | user:john.doe | lkduj... | 2023-09-28 12:08:23 | NULL | | ||
| 2 | user:demo.user | 2k1g2... | 2023-09-28 12:09:45 | 2023-09-28 12:09:10 | | ||
|
||
For this example, we would need a migration to add the `authn_sut_tokens` table. | ||
That would look something like this: | ||
|
||
```ruby | ||
Sequel.migration do | ||
change do | ||
create_table :authn_sut_tokens do | ||
primary_key :id | ||
foreign_key :role_id, :roles, type: String, null: false, on_delete: :cascade | ||
String :guid_hash, null: false, unique: true | ||
DateTime :expires_at, null: false | ||
DateTime :used_at | ||
end | ||
end | ||
end | ||
``` | ||
|
||
#### Authenticator | ||
|
||
The SUT authenticator will be implemented as a new authenticator plugin. The | ||
implementation will follow the existing authenticator plugin pattern, as | ||
documented in [AUTHENTICATORS.md](../AUTHENTICATORS.md) | ||
|
||
## Security | ||
|
||
Due to the fact that this feature will be used to authenticate to Conjur, it is | ||
critical that the implementation is secure. Threat modeling should be performed | ||
before implementation begins to identify potential security issues and ensure | ||
that they are addressed. There should be an additional security review of the | ||
implementation before it is merged. | ||
|
||
Much of the security of this feature will be provided by the underlying | ||
authenticator architecture, so we only need to be concerned with the security of | ||
the SUT and the implementation of the SUT authenticator plugin. | ||
|
||
## Testing | ||
|
||
### Unit Tests | ||
|
||
Unit tests should cover virtually all lines of code in the implementation. | ||
|
||
### Integration Tests | ||
|
||
Integration tests should cover the following scenarios | ||
|
||
| Scenario | Path Type | Test Purpose | Failure Scenarios | Details | | ||
|----------|-----------|--------------|-------------------|---------| | ||
| Generate SUT | Happy | Verify that a SUT can be generated for a user | | | | ||
| Generate SUT - Invalid credentials | Sad | Verify that a SUT cannot be generated for a user with invalid credentials | | | | ||
| Generate SUT - Invalid authenticator | Sad | Verify that a SUT cannot be generated for a user with an invalid authenticator | | | | ||
| Generate SUT - Disabled authenticator | Sad | Verify that a SUT cannot be generated for a user with a disabled authenticator | | | | ||
| Generate SUT - Authenticator not enabled for user | Sad | Verify that a SUT cannot be generated for a disabled user | | | | ||
| Authenticate with SUT | Happy | Verify that a user can authenticate to Conjur with a SUT | | | | ||
| Authenticate with SUT - Invalid SUT | Sad | Verify that a user cannot authenticate to Conjur with an invalid SUT | | | | ||
| Authenticate with SUT - Expired SUT | Sad | Verify that a user cannot authenticate to Conjur with an expired SUT | | | | ||
| Authenticate with SUT - Used SUT | Sad | Verify that a user cannot authenticate to Conjur with a used SUT | | | | ||
| Authenticate with SUT - Invalid authenticator | Sad | Verify that a user cannot authenticate to Conjur with an invalid authenticator | | | | ||
| Authenticate with SUT - Disabled authenticator | Sad | Verify that a user cannot authenticate to Conjur with a disabled authenticator | | | | ||
| Authenticate with SUT - Authenticator not enabled for user | Sad | Verify that a user cannot authenticate to Conjur with a disabled user | | | | ||
|
||
## Project Cost & Schedule | ||
|
||
For the following table, "Effort" is estimated in terms of developer days. "Risk" | ||
is an estimate of the risk of missing said estimate. Low risk means high likelihood | ||
of hitting the estimate, while high risk means low likelihood of hitting the estimate. | ||
|
||
| Task | Effort | Risk | | ||
|------|--------|------| | ||
|
||
<!-- TODO: Task list --> |
Oops, something went wrong.