Skip to content
Open
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
713 changes: 709 additions & 4 deletions crates/openshell-cli/src/commands/gateway.rs

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions crates/openshell-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,12 @@ enum GatewayCommands {
#[arg(long, conflicts_with = "remote")]
local: bool,

/// Keep an existing complete mTLS bundle in the gateway config
/// directory instead of refreshing it from the package-managed TLS
/// directory. Use this when the bundle is externally managed.
#[arg(long, requires = "local")]
preserve_mtls_bundle: bool,

/// Register as an OIDC-authenticated gateway using the given issuer URL.
/// The server must be configured with `--oidc-issuer` matching this URL.
#[arg(long, conflicts_with = "remote")]
Expand Down Expand Up @@ -2682,6 +2688,7 @@ async fn run_async() -> Result<()> {
name,
remote,
local,
preserve_mtls_bundle,
oidc_issuer,
oidc_client_id,
oidc_audience,
Expand All @@ -2692,6 +2699,7 @@ async fn run_async() -> Result<()> {
name.as_deref(),
remote.as_deref(),
local,
preserve_mtls_bundle,
oidc_issuer.as_deref(),
&oidc_client_id,
oidc_audience.as_deref(),
Expand Down
11 changes: 11 additions & 0 deletions crates/openshell-cli/src/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,17 @@ pub fn build_rustls_config(materials: &TlsMaterials) -> Result<rustls::ClientCon
.into_diagnostic()
}

/// Validate raw TLS materials using the same Rustls configuration path used
/// by the CLI client, without exposing the internal material container.
pub fn validate_rustls_materials(ca: &[u8], cert: &[u8], key: &[u8]) -> Result<()> {
let materials = TlsMaterials {
ca: ca.to_vec(),
cert: cert.to_vec(),
key: key.to_vec(),
};
build_rustls_config(&materials).map(drop)
}

#[derive(Debug)]
struct InsecureServerCertVerifier;

Expand Down
3 changes: 3 additions & 0 deletions crates/openshell-cli/tests/mtls_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,7 @@ async fn gateway_add_mtls_loopback_uses_explicit_gateway_name() {
Some("k8s"),
None,
true,
false,
None,
"openshell-cli",
None,
Expand Down Expand Up @@ -815,6 +816,7 @@ async fn gateway_add_mtls_loopback_without_name_uses_openshell_default() {
None,
None,
true,
false,
None,
"openshell-cli",
None,
Expand Down Expand Up @@ -856,6 +858,7 @@ async fn gateway_add_mtls_loopback_explicit_name_does_not_fallback_to_openshell_
Some("k8s"),
None,
true,
false,
None,
"openshell-cli",
None,
Expand Down
16 changes: 15 additions & 1 deletion deploy/rpm/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,23 @@ CLI:
mkdir -p ~/.config/openshell/gateways/openshell/mtls/
cp ca.crt tls.crt tls.key ~/.config/openshell/gateways/openshell/mtls/

openshell gateway add --local https://<gateway-hostname>:17670
openshell gateway add --local --name openshell --preserve-mtls-bundle https://<gateway-hostname>:17670
```

`--name openshell` matters: without it the CLI derives the gateway name from
the endpoint hostname, looks for the bundle under
`~/.config/openshell/gateways/<gateway-hostname>/mtls/`, and never sees the
`openshell` bundle copied above.

`--preserve-mtls-bundle` matters: without it, `gateway add --local`
refreshes the gateway's bundle from the package-managed TLS directory,
replacing the externally-managed certificates copied above. With the flag
the pre-provisioned bundle is kept as-is. A bundle whose files are present
but unusable (for example an empty or truncated key from a failed copy)
fails registration with an error naming the file instead of connecting with
broken credentials — a broken bundle is never silently repaired or
discarded.

### Firewall

For remote access, open the gateway port in firewalld:
Expand Down
3 changes: 2 additions & 1 deletion docs/how-it-works/gateways/authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ Set these environment variables before starting the gateway:
For local access, the server certificate must be valid for the endpoint the CLI uses. Include `localhost`, `127.0.0.1`, and `::1` in the certificate SANs when users connect to a local gateway through loopback.

Package-managed local gateways generate this bundle automatically for the `openshell` gateway name. Homebrew registers `https://localhost:17670`; Debian and RPM use `https://127.0.0.1:17670`.
When you register a package-managed local gateway with `openshell gateway add <endpoint> --local --name openshell`, the CLI refreshes its mTLS bundle from the package-managed TLS directory.
When you register a package-managed local gateway with `openshell gateway add <endpoint> --local --name openshell`, the CLI imports the mTLS bundle from the package-managed TLS directory, refreshing any complete bundle already stored for the gateway — the documented `gateway remove` / `gateway add` flow rotates package credentials without deleting anything manually. A bundle you placed under `~/.config/openshell/gateways/<name>/mtls/` yourself (for example, externally-managed certificates) is kept instead when you pass `--preserve-mtls-bundle`. A partial or unusable bundle always fails registration with the missing or broken paths so interrupted provisioning is never silently repaired or discarded.

On Homebrew, the gateway service also mirrors the gateway CA into `$HOME/.local/state/openshell/homebrew/tls` before startup so Docker Desktop can bind-mount gateway trust into supervisor containers. The driver does not mount the user client certificate or private key.

The CLI loads its mTLS bundle from `~/.config/openshell/gateways/<name>/mtls/`:
Expand Down
4 changes: 3 additions & 1 deletion docs/how-it-works/gateways/container-deployment.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,11 @@ sudo cp /var/lib/openshell/tls/ca.crt \
/var/lib/openshell/tls/client/tls.crt \
/var/lib/openshell/tls/client/tls.key "$mtls"/
sudo chown "$USER" "$mtls"/*
openshell gateway add https://127.0.0.1:8080 --local --name local
openshell gateway add https://127.0.0.1:8080 --local --name local --preserve-mtls-bundle
```

`--preserve-mtls-bundle` keeps the copied container bundle: without it, `gateway add --local` refreshes the CLI bundle from the package-managed TLS directory when one exists on this machine, which would replace the container gateway's client certificate with the package's.

## Using Podman

The Podman driver runs sandboxes as rootless containers through the user Podman socket, and [Sandbox Runtimes](/how-it-works/sandboxes/runtimes#podman-driver) lists its requirements. The commands in this section assume rootless Podman. Enable the socket for your user:
Expand Down
Loading