GitHub mirror is no longer maintained; git.simpleremoter.com is the live host for both SimpleRemoter and yama-issue-token. Update source-code link, both clone commands, and the licensing-package tree link. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
121 lines
4.1 KiB
Markdown
121 lines
4.1 KiB
Markdown
# yama-issue-token
|
|
|
|
CLI to mint customer JWTs (RS256) for the YAMA Go server's **License Server**
|
|
(`/license/sign`, `/license/heartbeat`).
|
|
|
|
A thin shell around [`licensing.Issue()`][issue] in the YAMA Go server —
|
|
all validation (tier rules, TTL floor, `sub` required) lives there, so
|
|
this tool stays in sync as the licensing package evolves.
|
|
|
|
[issue]: https://git.simpleremoter.com/yuanyuanxiang/SimpleRemoter/src/branch/main/server/go/licensing/server.go
|
|
|
|
## Status
|
|
|
|
Personal hobby project, MIT license. Not a commercial product, no SLA.
|
|
|
|
## Build
|
|
|
|
This module uses a local `replace` directive to consume the YAMA `licensing`
|
|
package from a sibling checkout — `go install` from a fresh clone will fail.
|
|
Build it locally:
|
|
|
|
```bash
|
|
git clone https://git.simpleremoter.com/yuanyuanxiang/SimpleRemoter.git ../SimpleRemoter
|
|
# yama-issue-token expects YAMA at ../YAMA/server/go (see go.mod replace);
|
|
# if you cloned as SimpleRemoter, either rename or adjust the replace line.
|
|
|
|
git clone https://git.simpleremoter.com/yuanyuanxiang/yama-issue-token.git
|
|
cd yama-issue-token
|
|
go build -o yama-issue-token .
|
|
```
|
|
|
|
`go.mod` currently pins:
|
|
|
|
```go
|
|
replace github.com/yuanyuanxiang/SimpleRemoter/server/go => ../YAMA/server/go
|
|
```
|
|
|
|
This is kept on purpose during local development — the tool tracks the
|
|
in-tree `licensing` package. A pinned-version setup may come later.
|
|
|
|
## One-time RSA keypair
|
|
|
|
The License Server verifies issued JWTs with the public key. Generate once,
|
|
keep the **private key on the issuer machine only**:
|
|
|
|
```bash
|
|
openssl genrsa -out license_priv.pem 2048
|
|
openssl rsa -in license_priv.pem -pubout -out license_pub.pem
|
|
```
|
|
|
|
Hand `license_pub.pem` to the License Server (`YAMA_LICENSE_PUBLIC_KEY`).
|
|
The private key stays with whoever is issuing tokens.
|
|
|
|
## Usage
|
|
|
|
```text
|
|
yama-issue-token -priv <license_priv.pem> -sub <customer-id> [options]
|
|
|
|
Required:
|
|
-priv RSA private key PEM (PKCS#1 or PKCS#8).
|
|
-sub Customer ID — unique string; lands in the JWT "sub" claim.
|
|
|
|
Options:
|
|
-tier trial | paid (default: trial)
|
|
-max Max concurrent devices (trial default: 20;
|
|
paid: REQUIRED, no default)
|
|
-days Token TTL in days (default: 365; minimum: 1 hour)
|
|
-out Write token to this file (0600) instead of stdout
|
|
```
|
|
|
|
The signed JWT goes to **stdout** (single line, no trailing whitespace).
|
|
Issuance details (sub / tier / max / expires) go to **stderr** and remain
|
|
visible when stdout is redirected.
|
|
|
|
### Examples
|
|
|
|
```bash
|
|
# Trial customer, 5 devices, 30 days, print to terminal
|
|
yama-issue-token -priv license_priv.pem -sub acme-trial -tier trial -max 5 -days 30
|
|
|
|
# Paid customer, 200 devices, 1 year, write to file (mode 0600)
|
|
yama-issue-token -priv license_priv.pem -sub acme-corp -tier paid -max 200 -out token-acme.jwt
|
|
|
|
# Pipe into env var (Linux/macOS shell)
|
|
export YAMA_LICENSE_TOKEN=$(yama-issue-token -priv license_priv.pem -sub acme -tier paid -max 100)
|
|
```
|
|
|
|
## Tier semantics
|
|
|
|
| Tier | `-max` default | Notes |
|
|
| ------- | -------------- | ----------------------------------------------- |
|
|
| `trial` | 20 | Inherits the C++ anti-proxy RTT logic on server |
|
|
| `paid` | required | No default — must be supplied explicitly |
|
|
|
|
## Integration
|
|
|
|
Set on the customer's Go server (RemoteSigner mode):
|
|
|
|
```bash
|
|
YAMA_LICENSE_SERVER=https://license.example.com
|
|
YAMA_LICENSE_TOKEN=<the JWT this tool produced>
|
|
```
|
|
|
|
The customer's server never sees the master HMAC key — it HTTPS-POSTs to
|
|
`/license/sign` for each new device login, then caches the signature for
|
|
24h (`YAMA_LICENSE_OFFLINE_HRS`).
|
|
|
|
See the YAMA repo for the License Server side:
|
|
[`server/go/licensing/`](https://git.simpleremoter.com/yuanyuanxiang/SimpleRemoter/src/branch/main/server/go/licensing).
|
|
|
|
## Security
|
|
|
|
- Private key has no business leaving the issuer host. `.gitignore` excludes
|
|
`*.pem`, `*.key`, `*.jwt`, `token-*.jwt`, `license_priv*`, `license_pub*`.
|
|
- `-out` writes with mode `0600`.
|
|
- JWT `alg` is locked to `RS256` server-side — `alg:none` attacks are rejected.
|
|
|
|
## License
|
|
|
|
MIT
|