Factory Helper
Onboarding without a GCP account
Section titled “ Onboarding without a GCP account”Every vehicle starts with a factory certificate — its birth certificate. It is what the platform checks before it issues anything else, so nothing works until a vehicle has one.
Until now, getting one meant having credentials for the Google Cloud project that hosts the platform, because the certificate was requested from the certificate authority directly. That is workable for the team running the platform and unusable for anyone else: a partner integrating a device, a colleague on a test bench, a workshop participant.
The Factory Helper removes that requirement. It is a small service on the platform that issues factory identities on request. A caller needs two things:
- a client secret for the Keycloak client that is allowed to ask, and
- an internet connection.
No Google Cloud account, no gcloud, no IAM role.
What you need before you start
Section titled “What you need before you start”| Where it comes from | |
|---|---|
| Base domain | the BASE_DOMAIN of the platform you are onboarding to |
| Client secret | stored during deployment as the Secret Manager secret FACTORY_OPERATOR_CLIENT_SECRET; the platform operator passes it to you |
jq | your package manager |
The operator reads the secret once and hands it over; everything else the scripts fetch themselves. Trust certificates come from a public, read-only bucket over plain HTTPS, which is why no credentials are involved on your side.
Onboarding a vehicle end to end
Section titled “Onboarding a vehicle end to end”Both sample clients ship with a launcher that walks the whole path: get a factory identity, register it, obtain an operational certificate and a token, and start publishing telemetry.
cd sample-clients/vehicle-client/
FACTORY_OPERATOR_CLIENT_SECRET="<secret>" \ ./run-vehicle-client-factory.sh --vin VEHICLE001 --base-domain <your-domain>cd sample-clients/python/
FACTORY_OPERATOR_CLIENT_SECRET="<secret>" \ ./run-python-client-factory.sh --vin VEHICLE002 --base-domain <your-domain>If you run the script from a checkout that still has the platform’s
.bootstrap_env, the base domain is taken from there and --base-domain can be
left out.
What the script does
Section titled “What the script does”-
Fetches the trust certificates From the platform’s public bucket, fresh on every run — a cached copy may belong to a different environment or to a certificate that has since been rotated.
-
Obtains an operator token From Keycloak, using the client secret.
-
Requests a factory identity The platform issues a certificate for your VIN and returns it together with its chain. The script stores both next to the client and restricts the key file to your user.
-
Runs the client Registration, operational certificate, token, NATS — the normal client lifecycle, now with an identity the platform trusts.
A successful run prints each stage as it passes:
✓ Trust certs downloaded (fresh)✓ Operator token obtained✓ Factory identity issued for VIN VEHICLE001✓ Build complete*** Running vehicle-client... ***✓ Registered and obtained operational certificate✓ Authenticated with Keycloak✓ NATS smoke test passedStarting continuous telemetry publishing...Running the script again reuses the identity it already has — it prints
✓ Factory identity exists and goes straight on. To start over with a fresh
identity, delete the factory certificate and key beside the client.
Calling the endpoint directly
Section titled “Calling the endpoint directly”The launchers are convenience wrappers. Integrating your own device means calling the endpoint yourself:
POST https://factory.<base-domain>:8443/v1/factory-certificatesAuthorization: Bearer <operator token>There are two ways to use it, and which one you want depends on the device:
| Send | You receive | Use when | |
|---|---|---|---|
| Your own CSR | {"csr": "<PEM>"} | certificate and chain | the device can generate a key — it never leaves the device |
| Server-side | {"vin": "VEHICLE001"} | certificate, chain and private key | a bench tool or script needs a complete identity in one call |
Prefer the first form wherever the device can manage a key of its own. The second exists because not every test setup can, and the response is marked never to be cached — but the key does travel over the connection, which the first form avoids entirely.
If you send a CSR, its common name must follow the platform’s convention,
VIN:<vin> DEVICE:<type>, and it must match the VIN you name in the request.