Skip to content
bobapplemacPublic

About

Securely run commands, shells, and SSH using process-scoped 1Password authentication and ephemeral SSH-agent sockets.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

18 Commits

Folders and files

Repository files navigation

opexec

opexec runs commands, shells, and OpenSSH clients in a process-scoped 1Password authentication context backed by an ephemeral SSH-agent socket.

The agent serves Ed25519 and RSA SSH Key items from 1Password. For RSA keys it honors the signature algorithm requested by OpenSSH, including legacy RSA/SHA-1; client and server SSH policy determines whether that algorithm is permitted.

Quick start

On Linux x64, download, verify, and install the latest release with:

curl -fsSL https://raw.githubusercontent.com/bobapplemac/opexec/main/scripts/install.sh | sh

Build and validation

The supported deployment target is Linux x64. Building requires Make plus either the .NET 10 SDK or Docker. Runtime use also requires the 1Password CLI (op) and, for opssh, OpenSSH (ssh) on PATH, with access to your configured 1Password account.

On Linux, the usual build is:

make

This publishes the self-contained, single-file executable at artifacts/publish/linux-x64/opexec. Publishing means creating a deployable local artifact; it does not upload the binary or create a GitHub Release.

The Make workflow automatically prefers a locally installed .NET 10 SDK so it benefits from the normal NuGet cache and has the shortest edit/build cycle. If the SDK is unavailable and Docker is installed, it uses the pinned SDK container instead. This selection applies to make build, make test, and make publish. The package and release workflows use the same selection for their build steps. Set BUILD_BACKEND to force either backend while retaining the same action vocabulary:

make publish BUILD_BACKEND=dotnet
make publish BUILD_BACKEND=docker

BUILD_BACKEND accepts auto (the default), dotnet, or docker, and can also be used with make build and make test.

make build places compiler output under artifacts/bin; it is intermediate build output and is not the installable single-file executable. make publish and the Visual Studio linux-x64 folder profile both place the deployable binary under artifacts/publish/linux-x64. Run make help for the complete target list.

Packages and GitHub releases

publish retains its standard .NET meaning: it creates a local deployable application. package is also local: it tests and publishes the application, then creates a versioned archive and SHA-256 checksum under artifacts/release:

make package

Creating a public GitHub Release is a separate, explicit external operation:

gh auth login
make release

make release requires a clean Linux checkout whose HEAD exactly matches origin/main. After its publication preflight passes, it runs the local package workflow and creates the corresponding rN Git tag and GitHub Release using the revision in src/Directory.Build.props. GH_TOKEN may be used instead of an interactive gh auth login session.

Published revisions are immutable. The release command refuses to replace an existing tag or GitHub Release; increment ProductRevision for a subsequent release.

The Docker backend requires Docker BuildKit and network access to restore NuGet packages and pull the SDK image on its first run.

The equivalent direct .NET commands, which remain suitable for Visual Studio and Windows development, are:

dotnet restore src/OpExec.slnx
dotnet build src/OpExec.slnx -c Release --artifacts-path artifacts
dotnet test src/OpExec.slnx -c Release --artifacts-path artifacts
dotnet publish src/OpExec/OpExec.csproj -p:PublishProfile=linux-x64

Run validation on Linux as well: some platform-specific tests return early on other operating systems. See test fixtures for scope and limitations.

Installation and usage

The release is one self-contained executable. Build and install it system-wide with the traditional Make workflow:

make
sudo make install

The unprivileged make step publishes the local binary. The privileged install step copies it to /usr/local/bin/opexec and creates the opshell and opssh aliases without rebuilding. Remove the system installation with:

sudo make uninstall

The Makefile does not invoke sudo; privilege elevation remains under the user's control.

To install a previously published or downloaded binary directly, run sudo ./opexec --install. A per-user installation uses $HOME/.local/bin instead:

./opexec --install --user

Use the corresponding --uninstall command, with --user when applicable, to remove an installation. Installation refuses unrelated existing files unless --force is explicitly supplied with --install.

To check GitHub for a newer stable release and install it, use the same scope and privilege level as the original installation:

sudo opexec --update
opexec --update --user

OpExec asks for confirmation before downloading. Pass -y or --yes to accept an available update non-interactively. Drafts and prereleases are not selected. Release archives are size-bounded, checked against their published SHA-256 sidecar, validated to contain only the opexec executable, and installed through the same atomic replacement path as --install.

opexec command argument
opshell
opssh root@example.com

Run an agent in the foreground:

opssh --agent

Start a detached agent and apply its socket to the current shell:

eval "$(opssh --agent --daemon)"

Stop that agent and clear its exported environment with:

eval "$(opssh --agent --stop)"

To stop every detached agent owned by the current user:

eval "$(opssh --agent --stop-all)"

Use opssh --agent --help for agent-mode options. Detached human sessions are not reauthenticated after invalidation. While a manually authenticated OpExec scope is running, it performs an authenticated, account-specific 1Password heartbeat every 5 minutes to prevent the normal inactivity timeout, with an initial post-start check after five seconds. If the session is revoked or cannot be renewed after bounded retries, sign in again and restart the scope.

The standalone opssh --help, opssh --version, and opssh --licenses long options are handled by OpExec. Native SSH short options such as -V, -v, and -q, and all long-option-looking arguments used as part of an SSH invocation, are passed to ssh unchanged.

See the architecture, foreground process execution, security hardening boundaries, and versioning policy for design details.

Contact and security

For general questions, contact Andrew J. Moore or open an issue on GitHub. Report suspected vulnerabilities privately to the same email address; see SECURITY.md for reporting guidance. Do not include credentials or sensitive account information in public issues.

License

OpExec is licensed under the MIT License. See LICENSE.txt for the license text. License texts and notices for all third-party libraries and runtime components bundled into the self-contained executable are retained in THIRD-PARTY-NOTICES.txt.

Print the complete embedded notice set from any installed alias with:

opexec --licenses
opshell --licenses
opssh --licenses
opssh --agent --licenses

Project disclaimer

OpExec is an independent project and is not affiliated with, endorsed by, or sponsored by 1Password. Product names and trademarks belong to their respective owners. The software is provided as-is under the MIT License, without warranty. Review the security boundaries before trusting it with credentials or using it on systems you administer.

About

Securely run commands, shells, and SSH using process-scoped 1Password authentication and ephemeral SSH-agent sockets.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages