Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ These crates are libraries two services build on; three rules keep them that way
unified-api and unified-gitops against your branch (see
[docs/development.md](docs/development.md#working-on-a-service-against-a-local-copy)).

`unified-auth` depends on `unified-secrets`, never the reverse.
`auth-rs` depends on `secrets-rs`, never the reverse.

## Code comments

Expand Down
70 changes: 35 additions & 35 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# by tag, so both crates move together and a tag names one consistent pair.
[workspace]
resolver = "3"
members = ["crates/unified-secrets", "crates/unified-auth"]
members = ["crates/secrets-rs", "crates/auth-rs"]

[workspace.package]
version = "0.2.0"
Expand All @@ -16,7 +16,7 @@ repository = "https://github.com/OpusProjects/auth"
# Versions the crates share, declared once (crates name them with
# `workspace = true`), so the two can never resolve different majors.
[workspace.dependencies]
unified-secrets = { path = "crates/unified-secrets" }
secrets-rs = { path = "crates/secrets-rs" }
# Vault's HTTP API. rustls instead of openssl to keep the build self-contained,
# the same stack the services already use.
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ A secrets and sign-in library for web services, written in Rust.
Auth holds what a service needs to read a credential and to sign a person in, in one place, so a
fix lands in every service that uses it at once instead of being copied from one to the next.

Two crates in one workspace, released together under one tag: `unified-secrets` resolves credentials
from environment variables, JSON files or HashiCorp Vault, and `unified-auth` signs people in with
Two crates in one workspace, released together under one tag: `secrets-rs` resolves credentials
from environment variables, JSON files or HashiCorp Vault, and `auth-rs` signs people in with
their directory account or an API key and keeps them signed in with a browser session.

---
Expand All @@ -34,8 +34,8 @@ their directory account or an API key and keeps them signed in with a browser se

| Document | What it covers |
|---|---|
| [Secrets](docs/secrets.md) | The `unified-secrets` crate: credentials, the backends, `build_chain` and caching |
| [Sign-in](docs/sign-in.md) | The `unified-auth` crate: LDAP, access rules, the login, API keys, sessions |
| [Secrets](docs/secrets.md) | The `secrets-rs` crate: credentials, the backends, `build_chain` and caching |
| [Sign-in](docs/sign-in.md) | The `auth-rs` crate: LDAP, access rules, the login, API keys, sessions |
| [Development](docs/development.md) | The workspace, the CI gates, and working on a service against a local copy |
| [Releasing](docs/releasing.md) | How release-please cuts a version, and how a service moves to it |

Expand Down
6 changes: 3 additions & 3 deletions crates/unified-auth/Cargo.toml → crates/auth-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "unified-auth"
description = "Sign-in for the unified tools: LDAP accounts, access rules, a throttled login, API keys and browser sessions"
name = "auth-rs"
description = "Sign-in for web services: LDAP accounts, access rules, a throttled login, API keys and browser sessions"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
Expand All @@ -12,7 +12,7 @@ readme = "../../README.md"
publish = false

[dependencies]
unified-secrets.workspace = true
secrets-rs.workspace = true
ldap3.workspace = true
rustls.workspace = true
rustls-pki-types.workspace = true
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ pub fn cookie_value<'h>(header: &'h str, name: &str) -> Option<&'h str> {

// The store, injected as a router Extension the way the key registry is.
// `new` rather than the tuple constructor, so a service's type alias
// (`Sessions = unified_auth::http::Sessions<Permissions>`) can build one: Rust
// (`Sessions = auth_rs::http::Sessions<Permissions>`) can build one: Rust
// lets an alias name a type, but not call a tuple struct's constructor.
pub struct Sessions<P>(pub Arc<SessionStore<P>>);

Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions crates/unified-auth/src/lib.rs → crates/auth-rs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// unified-auth — signing people in to the unified tools.
// auth-rs — signing people in to a web service.
//
// A person logs in with their directory account (LDAP / Active Directory);
// the directory says who they are and which groups they belong to, and the
Expand All @@ -15,7 +15,7 @@
// that checks them, browser sessions, CSRF — generic over each service's
// permissions type
//
// The service account's password comes through unified-secrets, like any
// The service account's password comes through secrets-rs, like any
// other credential. Shared by unified-api and unified-gitops: a fix here
// lands in both.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::sync::Mutex;
use std::time::{Duration, Instant};

use unified_secrets::SecretsPort;
use secrets_rs::SecretsPort;

use crate::directory::{DirectoryError, DirectoryLogin, DirectoryPort};
use crate::ldap::{AccessRule, LdapConfig};
Expand Down Expand Up @@ -204,7 +204,7 @@ mod tests {
use super::*;
use crate::directory::{DirectoryFuture, DirectoryUser};
use crate::ldap::rule_names;
use unified_secrets::mock::MockSecrets;
use secrets_rs::mock::MockSecrets;

// A service's rules, reduced to what the use case needs: who they name,
// and whether they make that person an admin.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
// directory, no network.
use std::sync::Once;

use auth_rs::directory::{DirectoryError, DirectoryLogin, DirectoryPort, DirectoryUser};
use auth_rs::ldap::LdapServer;
use auth_rs::ldap_directory::LdapDirectory;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use unified_auth::directory::{DirectoryError, DirectoryLogin, DirectoryPort, DirectoryUser};
use unified_auth::ldap::LdapServer;
use unified_auth::ldap_directory::LdapDirectory;

// One process-wide log subscriber, so every logged field is evaluated the
// same way whichever test happens to reach a log line first.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "unified-secrets"
description = "Credential resolution for the unified tools: environment variables, JSON files and HashiCorp Vault"
name = "secrets-rs"
description = "Credential resolution for services: environment variables, JSON files and HashiCorp Vault"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// unified-secrets — resolving credentials for the unified tools.
// secrets-rs — resolving credentials for a service.
//
// A credential is a reference written in configuration: it says WHERE its
// values live (environment variables, a JSON file, a HashiCorp Vault KV v2
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ use axum::http::{HeaderMap, StatusCode};
use axum::routing::{get, post};
use axum::{Json, Router};

use unified_secrets::credential::Credential;
use unified_secrets::env::EnvSecrets;
use unified_secrets::port::SecretsPort;
use unified_secrets::vault::{VaultConfig, VaultSecrets};
use secrets_rs::credential::Credential;
use secrets_rs::env::EnvSecrets;
use secrets_rs::port::SecretsPort;
use secrets_rs::vault::{VaultConfig, VaultSecrets};

async fn fake_vault() -> String {
let app = Router::new()
Expand Down
26 changes: 13 additions & 13 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ One Cargo workspace with two crates, sharing one version and one `Cargo.lock`.
```
Cargo.toml # the workspace: members, shared version, shared dependency versions
crates/
├── unified-secrets/src/ # credential, port, env, vault, cache, reloadable, chain, mock
└── unified-auth/src/ # directory, ldap_directory, ldap, login, http/ (auth, session)
├── secrets-rs/src/ # credential, port, env, vault, cache, reloadable, chain, mock
└── auth-rs/src/ # directory, ldap_directory, ldap, login, http/ (auth, session)
docs/ # this documentation
release-please-config.json # release-please: version files, changelog sections
.release-please-manifest.json # the last released version
```

`unified-auth` depends on `unified-secrets` (the LDAP bind credential is resolved through it), never
the reverse, so a tool that only needs secrets can depend on `unified-secrets` alone.
`auth-rs` depends on `secrets-rs` (the LDAP bind credential is resolved through it), never
the reverse, so a tool that only needs secrets can depend on `secrets-rs` alone.

---

Expand All @@ -51,15 +51,15 @@ than their pinned toolchain must fail here, not in their builds.
unified-api and unified-gitops name a release tag of this repository in their `Cargo.toml`.

```toml
unified-secrets = { git = "https://github.com/OpusProjects/auth", tag = "v0.1.0" }
unified-auth = { git = "https://github.com/OpusProjects/auth", tag = "v0.1.0" }
secrets-rs = { git = "https://github.com/OpusProjects/auth", tag = "v0.1.0" }
auth-rs = { git = "https://github.com/OpusProjects/auth", tag = "v0.1.0" }
```

Both lines name the same tag: the crates are released together. The services' `deny.toml` allows
this one git source (`[sources] allow-git`), which every other git dependency is refused by.

Moving a service to a new release is a `build:` pull request in the service that changes both tags
and its `Cargo.lock` (`cargo update -p unified-secrets -p unified-auth`).
and its `Cargo.lock` (`cargo update -p secrets-rs -p auth-rs`).

---

Expand All @@ -72,8 +72,8 @@ With auth checked out next to the service, add a `[patch]` section to the servic

```toml
[patch."https://github.com/OpusProjects/auth"]
unified-secrets = { path = "../auth/crates/unified-secrets" }
unified-auth = { path = "../auth/crates/unified-auth" }
secrets-rs = { path = "../auth/crates/secrets-rs" }
auth-rs = { path = "../auth/crates/auth-rs" }
```

Then run the service's own gates (`cargo clippy --all-targets -- -D warnings` and `cargo test`):
Expand All @@ -86,10 +86,10 @@ section before committing anything in the service.

New code goes in the crate whose job it is, with its tests in the same file.

- **A new secrets backend:** a `SecretsPort` adapter in `unified-secrets`, and a route to it in
- **A new secrets backend:** a `SecretsPort` adapter in `secrets-rs`, and a route to it in
`chain.rs`. The YAML fields it adds belong on `Credential`, strict like the rest.
- **A new way to sign in:** a `DirectoryPort` adapter, or a new use case beside `login.rs`, in
`unified-auth`; a new way to authenticate a request belongs in its `http` module.
`auth-rs`; a new way to authenticate a request belongs in its `http` module.
- **Anything one service needs and the other does not:** in that service, not here.

Every new line comes with the test that runs it; see [Tests and coverage](#tests-and-coverage).
Expand All @@ -103,8 +103,8 @@ Every line of both crates runs in a test, and the `test` check fails a pull requ
| Where | What goes there |
|---|---|
| `#[cfg(test)] mod tests` at the bottom of a file in `src/` | Unit tests of that file, including its private functions |
| `crates/unified-secrets/tests/vault_test.rs` | The Vault adapter against a fake Vault: a few axum routes on `127.0.0.1` |
| `crates/unified-auth/tests/ldap_directory_test.rs` | The LDAP adapter against a fake directory that speaks just enough LDAP (bind, search, unbind) |
| `crates/secrets-rs/tests/vault_test.rs` | The Vault adapter against a fake Vault: a few axum routes on `127.0.0.1` |
| `crates/auth-rs/tests/ldap_directory_test.rs` | The LDAP adapter against a fake directory that speaks just enough LDAP (bind, search, unbind) |

The suite needs no directory, Vault or network. Test code under `tests/` is not counted by
`cargo llvm-cov`, which is why the two fakes live there: their own error handling would otherwise
Expand Down
4 changes: 2 additions & 2 deletions docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,11 @@ gh workflow run build.yaml --ref release-please--branches--main
A release here changes nothing in the services until each one names the new tag.

In unified-api and unified-gitops, open a `build:` pull request (`build: move to auth v0.2.0`) that
changes the `tag` of both `unified-secrets` and `unified-auth` in `Cargo.toml` and refreshes the
changes the `tag` of both `secrets-rs` and `auth-rs` in `Cargo.toml` and refreshes the
lockfile:

```bash
cargo update -p unified-secrets -p unified-auth
cargo update -p secrets-rs -p auth-rs
```

The service's CI is the check that the release works there. A release that changes what a person
Expand Down
8 changes: 4 additions & 4 deletions docs/secrets.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Secrets

The `unified-secrets` crate: how a service turns a credential item into the values a script or a
The `secrets-rs` crate: how a service turns a credential item into the values a script or a
login needs. The principle every service follows: **configuration never holds a secret**.

A credential describes *where* each value lives, and the infrastructure (env vars, mounted files,
Expand Down Expand Up @@ -31,7 +31,7 @@ The crate is a port, its adapters, and the one function that wires them together
| `chain` | `build_chain` and `SecretsConfig`, the deprecated `secrets:` block of `config.yaml` |
| `mock` | `MockSecrets`, the test double |

The names a service uses most are re-exported at the crate root: `unified_secrets::{Credential,
The names a service uses most are re-exported at the crate root: `secrets_rs::{Credential,
CredentialType, SecretsPort, SecretsError, SecretsConfig, build_chain}`.

---
Expand Down Expand Up @@ -64,7 +64,7 @@ A service builds one `SecretsPort` from its loaded credentials, and resolves eve

```rust
let secrets: Arc<dyn SecretsPort> =
unified_secrets::build_chain(&config.credentials, &config.secrets_config);
secrets_rs::build_chain(&config.credentials, &config.secrets_config);
let values = secrets.resolve("cred-vcenter-aa1").await?; // {"username": ..., "password": ...}
```

Expand Down Expand Up @@ -113,7 +113,7 @@ chain with one built from the new configuration. Resolutions already running fin
`MockSecrets` answers from a map, so a service's tests need no environment variables or Vault.

```rust
let secrets = unified_secrets::mock::MockSecrets::new()
let secrets = secrets_rs::mock::MockSecrets::new()
.with("cred-ldap", [("username", "CN=svc"), ("password", "secret")]);
```

Expand Down
Loading
Loading