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

[GAP-8] HTTP auth runtime #44

Open
wants to merge 5 commits into
base: stranger80/GAP/basic_auth_runtime
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 169 additions & 20 deletions gaps/gap-8_basic_auth_runtime/gap-8_basic_auth_runtime.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,190 @@
---
gap: <to be assigned>
title: <The GAP title is a few words, not a complete sentence>
description: <Description is one full (short) sentence>
author: <a list of the author's or authors' name(s) and/or username(s), or name(s) and email(s), e.g. (use with the parentheses or triangular brackets): FirstName LastName (@GitHubUsername), FirstName LastName <foo@bar.com>, FirstName (@GitHubUsername) and GitHubUsername (@GitHubUsername)>
gap: 8
title: Basic auth runtime
description: A generic runtime for services secured by HTTP basic authentication.
author: mf (@mfranciszkiewicz)
status: Draft
type: <Feature, Standards, Meta>
requires (*optional): <GAP number(s)>
replaces (*optional): <GAP number(s)>
type: Feature
---

This is the template to be used for new GAP submissions. Note this has been heavily inspired by Ethereum [EIP template](https://github.com/ethereum/EIPs/blob/master/eip-template.md).
## Abstract

The GAP number will be assigned by an editor. A GAP summary document shall be submitted by opening a pull request with GAP-related files placed in `./gaps/gap-draft_title/` directory. To submit your GAP, please use an abbreviated title in the filename, `gap-draft_title.md`.
A generic runtime for services secured by HTTP basic authentication, provided on the Golem Network. The services
in subject are exposed to the Internet via host's (provider's) operating system.

## Abstract
Abstract is a multi-sentence (short paragraph) technical summary. This should be a very terse and human-readable version of the specification section. Someone should be able to read only the abstract to get the gist of what this specification does.
The runtime is responsible for managing access to the forementioned services via corresponding `.htpasswd`
files and for gathering API usage statistics, i.e. the number of API calls that an authenticated user made to a service.

The first iteration of the runtime will only support the `nginx` reverse-proxy server.

## Motivation
The motivation section should describe the "why" of this GAP. What problem does it solve? What benefit does it provide to the Golem ecosystem? What use cases does this GAP address?

The original runtime specification has been derived from the results of work on the Erigon and Lighthouse service
runtimes. It was concluded that this kind of runtime could be useful in case of a multitude of REST-based services,
which do not enforce their own security mechanism.

## Specification
The technical specification should describe the syntax and semantics of any new feature.

The following is a reviewed version of the [original specification](https://www.notion.so/golemnetwork/Basic-auth-runtime-specification-59b6d111e4de4426ac230e729222c91a):

- Provider should be able to add/remove services by adding/removing config files from some designated directory
- designated directory lookup order:
- `~/.local/share/ya-runtime-basic-auth`
- current working directory
- The runtime should control access to services by HTTP basic auth.
- There should be a separate access list for every service.
- Requestor should be able to pass in the access credentials (user name + password) – these should **not** be generated by the runtime. User name collision should be handled.
- Each activity is limited to a single pair of access credentials.
- Runtime should expose number of requests as a custom usage metric.
- Breakdown of requests count into particular service endpoints (i.e. URL paths) is a nice to have feature.
- Supported HTTP servers: `nginx` (open source)


### Request counter implementation

The web server needs to be configured with a log format containing the authenticated user's name and the requested url.
The log file will be monitored and parsed for the purpose of gathering statistics.

`nginx` example:

```
log_format main '[$time_local] [$remote_user] [$remote_addr] '
'"$request_method $scheme://$host$request_uri $server_protocol" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time';
```

[var reference](https://nginx.org/en/docs/varindex.html)

[log-specific var reference](https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format)

### Runtime implementation

Base the implementation on [ya-runtime-sdk](https://github.com/golemfactory/ya-runtime-sdk)
- use [ya-runtime-basic-auth](https://github.com/golemfactory/yagna-service-erigon/tree/master/ya-runtime-basic-auth) as a starting point
- refer to [this comment](https://github.com/golemfactory/yagna-service-erigon/pull/47#issuecomment-983924928) for general guidance
- (htpasswd) port the `htpasswd.sh` script to Rust, e.g. using the `htpasswd-verify` crate, an implementation of the `apr1` digest and a `.htpasswd` formatter

#### Environment

Use a custom implementation of an `Env` trait for dynamically setting the runtime name and thus, the automatic choosing of the configuration file during startup.

An example can be found [here](https://github.com/golemfactory/ya-runtime-sdk/blob/mf/dynamic-rt-name/examples/environment/src/main.rs).

#### Command line arguments

Command line arguments should accept a runtime name parameter.

An example can be found [here](https://github.com/golemfactory/ya-runtime-sdk/blob/mf/dynamic-rt-name/examples/environment/src/main.rs).

#### Configuration

The configuration `struct` / `enum` should be de-serializable from all variants of configuration files (i.e., all service types) and contain the following information:

- service binary location
- nginx access log location
- nginx `.htpasswd` file location
- HTTP URIs reserved for the service (regex?)

#### Background jobs

1. Nginx log parser

Monitors the nginx access log file and counts the number of requests made by the current user.
mfranciszkiewicz marked this conversation as resolved.
Show resolved Hide resolved

2. Daemon counter updater

Periodically updates the custom counter value (total requests made by the user), extracted from the nginx access log file.
An example of a custom counter can be found [here](https://github.com/golemfactory/ya-test-runtime-counters/blob/main/src/main.rs).

#### `Runtime` trait implementation

1. `deploy`

- **in background**, start an instance of `erigolem` / `lighthouse` (if not running)
and wait until the application is ready to accept commands.

2. `start`

- none

3. `run`

- `credentials <username> <password>`

Sets the credentials that will be used in the current activity. If a username exists,
returns an error (with a proper message outputted to `stderr`); the runtime is terminated.

- `counter <name> <username> <password>` (optional)

Reads the specific counter value for a given user. The foreseen counter
names will be set to the requested URIs (locations) configured in nginx.
nieznanysprawiciel marked this conversation as resolved.
Show resolved Hide resolved

4. `transfer`

- none

5. `offer-template`

- if the server supports HTTPS, include a `https` runtime capability in an offer
- (optional) in case of self-signed certificates, add a property containing
the certificate (name TBD)
nieznanysprawiciel marked this conversation as resolved.
Show resolved Hide resolved

6. `test`

- executes the managed service binary and tries to parse the standard output of a sample command, e.g.`<binary> --version`
- (optional) performs (idempotent) requests to REST API endpoints of supported services
- (optional) performs a public IP check

### Deployment

Each service should be assigned its own runtime name and use the common `ya-runtime-basic-auth` binary, e.g.:

```json
[
{
"name": "ya-runtime-erigon",
"version": "0.1.0",
"supervisor-path": "exe-unit",
"runtime-path": "ya-runtime-basic-auth/ya-runtime-basic-auth",
"description": "The Basic-Auth runtime for the Erigon service",
"extra-args": [
"--runtime-managed-image",
👉 "--runtime-arg", "ya-runtime-erigon"
]
}
]
```

depending on the installation method, located at:
- `/usr/lib/yagna/plugins/ya-runtime-erigon.json` (manual or `deb` installation)
- `~/.local/lib/yagna/plugins/ya-runtime-erigon.json` (installer script)


## Rationale
The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work.

Parsing access logs for the purpose of gathering statistics is the least complex of other possible solutions:

- authentication endpoint (extra authentication server)
- authentication lua script
- nginx module
- reverse proxy server

The chosen approach may prove to perform poorly when access is offered to hundreds or thousands of users.

## Backwards Compatibility
All GAPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The GAP **must** explain how the author proposes to deal with these incompatibilities.

TBD

## Test Cases
Test cases are very useful in summarizing the scope and specifics of a GAP. If the test suite is too large to reasonably be included inline, then consider adding it as one or more files in `./gaps/gap-draft_title/` directory.

## [Optional] Reference Implementation
An optional section that contains a reference/example implementation that people can use to assist in understanding or implementing this specification. If the implementation is too large to reasonably be included inline, then consider adding it as one or more files in `./gaps/gap-draft_title/`.
TBD

## Security Considerations
All GAPs must contain a section that discusses the security implications/considerations relevant to the proposed change. Include information that might be important for security discussions, surfaces risks and can be used throughout the life cycle of the proposal. E.g. include security-relevant design decisions, concerns, important discussions, implementation-specific guidance and pitfalls, an outline of threats and risks and how they are being addressed.

- the provider needs to properly configure TLS certificates so that the authentication credentials
cannot be sniffed (i.e. they won't be sent as plain text)
- self-signed certificates need to be included in the offer in order to prevent Man In The Middle attacks

## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).