You've already forked hubmanager
feat: add AES-256-CBC encrypted password storage (v0.2.0)
Add `login --save --encrypt` flag: passwords are encrypted with openssl AES-256-CBC (PBKDF2) and stored as `enc:<base64>` in the config file. A master passphrase is prompted once per session and cached in memory. Both load_config() and resolve_registry_alias() detect the enc: prefix and decrypt transparently. The passphrase is passed to openssl via a temp file to avoid argv/env exposure. openssl is an optional dependency, checked on demand. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
69
README.md
69
README.md
@@ -7,6 +7,7 @@ A Bash CLI tool to manage Docker Registry images remotely. Supports Docker Hub a
|
||||
- **Bash** 4.0+
|
||||
- **curl**
|
||||
- **jq**
|
||||
- **openssl** *(optional — required only when using encrypted config values)*
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -25,6 +26,10 @@ install -m 755 hubmanager ~/bin/hubmanager
|
||||
hubmanager login --registry https://registry.example.com \
|
||||
--user admin --password secret --save
|
||||
|
||||
# Save with password encrypted at rest
|
||||
hubmanager login --registry https://registry.example.com \
|
||||
--user admin --password secret --save --encrypt
|
||||
|
||||
# List all repositories
|
||||
hubmanager list
|
||||
|
||||
@@ -74,9 +79,37 @@ hubmanager --registry staging list
|
||||
hubmanager --registry hub tags myuser/myapp
|
||||
```
|
||||
|
||||
### Encrypted credentials
|
||||
|
||||
Use `login --save --encrypt` to store the password encrypted with AES-256-CBC.
|
||||
A master passphrase is prompted at save time (with confirmation) and on every subsequent
|
||||
invocation that reads the config file. Requires `openssl`.
|
||||
|
||||
```bash
|
||||
hubmanager login --registry https://registry.example.com \
|
||||
--user admin --password secret --save --encrypt
|
||||
# New master passphrase: ****
|
||||
# Confirm master passphrase: ****
|
||||
# Login Succeeded — bearer auth, registry: https://registry.example.com
|
||||
# Credentials saved to /home/user/.hubmanager.conf
|
||||
# Password stored encrypted (AES-256-CBC). Master passphrase required on each use.
|
||||
```
|
||||
|
||||
The config file stores an `enc:` prefixed ciphertext:
|
||||
|
||||
```text
|
||||
REGISTRY=https://registry.example.com
|
||||
USERNAME=admin
|
||||
PASSWORD=enc:U2FsdGVkX1+...base64ciphertext...
|
||||
```
|
||||
|
||||
The `enc:` prefix also works for named alias passwords (`REGISTRY_<ALIAS>_PASSWORD`).
|
||||
On every command that reads the config, the master passphrase is prompted once and cached
|
||||
for the duration of the session.
|
||||
|
||||
## Global Options
|
||||
|
||||
```
|
||||
```text
|
||||
hubmanager [OPTIONS] <command> [COMMAND OPTIONS]
|
||||
|
||||
-r, --registry <url> Registry base URL
|
||||
@@ -98,11 +131,12 @@ hubmanager [OPTIONS] <command> [COMMAND OPTIONS]
|
||||
|
||||
### `login` — Test and save credentials
|
||||
|
||||
```
|
||||
hubmanager login [--registry URL] [--user USER] [--password PASS] [--save]
|
||||
```text
|
||||
hubmanager login [--registry URL] [--user USER] [--password PASS] [--save] [--encrypt]
|
||||
```
|
||||
|
||||
Validates credentials against the registry. Use `--save` to write them to the config file.
|
||||
Add `--encrypt` to store the password encrypted with AES-256-CBC (requires `openssl`).
|
||||
|
||||
```bash
|
||||
hubmanager login --registry https://registry.example.com \
|
||||
@@ -115,7 +149,7 @@ hubmanager login --registry https://registry.example.com \
|
||||
|
||||
### `list` — List repositories
|
||||
|
||||
```
|
||||
```text
|
||||
hubmanager list [--limit N] [--last REPO]
|
||||
```
|
||||
|
||||
@@ -139,7 +173,7 @@ hubmanager list --json | jq '.repositories[]'
|
||||
|
||||
### `tags` — List tags for an image
|
||||
|
||||
```
|
||||
```text
|
||||
hubmanager tags <image> [--limit N] [--last TAG]
|
||||
```
|
||||
|
||||
@@ -162,7 +196,7 @@ hubmanager tags myuser/myapp --json | jq '.tags[]'
|
||||
|
||||
### `inspect` — Show image details
|
||||
|
||||
```
|
||||
```text
|
||||
hubmanager inspect <image>:<tag|digest> [--platform OS/ARCH]
|
||||
```
|
||||
|
||||
@@ -201,7 +235,7 @@ hubmanager inspect myuser/myapp:latest --json | jq .
|
||||
|
||||
### `delete` — Delete a tag or manifest
|
||||
|
||||
```
|
||||
```text
|
||||
hubmanager delete <image>:<tag|digest> [--yes]
|
||||
```
|
||||
|
||||
@@ -225,9 +259,11 @@ hubmanager delete myuser/myapp@sha256:abc123... --yes
|
||||
|
||||
### `copy` — Copy or retag an image
|
||||
|
||||
```
|
||||
```text
|
||||
hubmanager copy <src-image>:<tag> <dst-image>:<tag> [options]
|
||||
```
|
||||
|
||||
```text
|
||||
Options:
|
||||
--src-registry URL Source registry (default: global --registry)
|
||||
--dst-registry URL Destination registry (default: global --registry)
|
||||
@@ -239,11 +275,13 @@ Options:
|
||||
```
|
||||
|
||||
**Same-registry retag** — attempts cross-repo blob mount (no data transfer):
|
||||
|
||||
```bash
|
||||
hubmanager copy myuser/myapp:v1.2.3 myuser/myapp:stable
|
||||
```
|
||||
|
||||
**Cross-registry copy** — streams blobs from source to destination:
|
||||
|
||||
```bash
|
||||
hubmanager copy myuser/myapp:latest \
|
||||
--src-registry https://registry-1.docker.io \
|
||||
@@ -252,6 +290,7 @@ hubmanager copy myuser/myapp:latest \
|
||||
```
|
||||
|
||||
**Copy specific platform** from a multi-arch image:
|
||||
|
||||
```bash
|
||||
hubmanager copy nginx:latest myuser/nginx-amd64:latest --platform linux/amd64
|
||||
```
|
||||
@@ -260,7 +299,7 @@ hubmanager copy nginx:latest myuser/nginx-amd64:latest --platform linux/amd64
|
||||
|
||||
### `prune` — Delete outdated tags
|
||||
|
||||
```
|
||||
```text
|
||||
hubmanager prune <image> [options]
|
||||
|
||||
Options:
|
||||
@@ -300,7 +339,7 @@ hubmanager prune myuser/myapp --keep 1 --no-exclude --dry-run
|
||||
hubmanager automatically detects the authentication method by probing the registry's `/v2/` endpoint:
|
||||
|
||||
| Registry type | Auth method |
|
||||
|---|---|
|
||||
| --- | --- |
|
||||
| Docker Hub | Bearer tokens via `auth.docker.io` |
|
||||
| Harbor, self-hosted with token server | Bearer tokens via registry-configured realm |
|
||||
| Basic-auth self-hosted | HTTP Basic Auth on every request |
|
||||
@@ -311,7 +350,7 @@ Bearer tokens are cached in memory for the duration of the session and refreshed
|
||||
### Docker Hub notes
|
||||
|
||||
- `list` uses the Docker Hub REST API (`hub.docker.com`) because the `_catalog` endpoint is restricted on Docker Hub.
|
||||
- `delete` is not supported via the v2 API on Docker Hub. Use the web UI at https://hub.docker.com.
|
||||
- `delete` is not supported via the v2 API on Docker Hub. Use the web UI at <https://hub.docker.com>.
|
||||
- `prune` is not supported on Docker Hub for the same reason.
|
||||
|
||||
---
|
||||
@@ -341,7 +380,7 @@ hubmanager prune myapp --keep 3 --yes --json
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| --- | --- |
|
||||
| 0 | Success |
|
||||
| 1 | General / usage error |
|
||||
| 2 | Authentication failure |
|
||||
@@ -380,12 +419,12 @@ hubmanager copy myuser/myapp:staging myuser/myapp:production
|
||||
## Configuration reference
|
||||
|
||||
| Key | Description |
|
||||
|-----|-------------|
|
||||
| --- | --- |
|
||||
| `REGISTRY` | Default registry URL |
|
||||
| `USERNAME` | Default username |
|
||||
| `PASSWORD` | Default password or token |
|
||||
| `PASSWORD` | Default password or token; prefix with `enc:` for encrypted values |
|
||||
| `REGISTRY_<ALIAS>_URL` | URL for a named registry alias |
|
||||
| `REGISTRY_<ALIAS>_USERNAME` | Username for a named alias |
|
||||
| `REGISTRY_<ALIAS>_PASSWORD` | Password for a named alias |
|
||||
| `REGISTRY_<ALIAS>_PASSWORD` | Password for a named alias (supports `enc:` prefix) |
|
||||
|
||||
Aliases are case-insensitive and treat `-` as `_`. For example, alias `my-reg` maps to `REGISTRY_MY_REG_URL`.
|
||||
|
||||
Reference in New Issue
Block a user