From 8d181ee90b41640d66c10dfce7fc387c0868b5d4 Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Thu, 12 Feb 2026 18:29:04 +0300 Subject: [PATCH 1/2] upgrade gcloud --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4697218..351fa71 100644 --- a/Dockerfile +++ b/Dockerfile @@ -76,16 +76,16 @@ RUN echo $TZ > /etc/timezone && \ # Install yq (architecture-aware) RUN ARCH=$(uname -m) && \ if [ "$ARCH" = "x86_64" ]; then ARCH="amd64"; elif [ "$ARCH" = "aarch64" ]; then ARCH="arm64"; fi && \ - curl -sL https://github.com/mikefarah/yq/releases/download/v4.50.1/yq_linux_${ARCH}.tar.gz | tar xz && \ + curl -sL https://github.com/mikefarah/yq/releases/download/v4.52.2/yq_linux_${ARCH}.tar.gz | tar xz && \ mv yq_linux_${ARCH} /usr/bin/yq && \ rm -rf /tmp/* # Install Google Cloud SDK (architecture-aware) RUN ARCH=$(uname -m) && \ if [ "$ARCH" = "x86_64" ]; then \ - curl -sSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-551.0.0-linux-x86_64.tar.gz" -o google-cloud-sdk.tar.gz; \ + curl -sSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-556.0.0-linux-x86_64.tar.gz" -o google-cloud-sdk.tar.gz; \ elif [ "$ARCH" = "aarch64" ]; then \ - curl -sSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-551.0.0-linux-arm.tar.gz" -o google-cloud-sdk.tar.gz; \ + curl -sSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-556.0.0-linux-arm.tar.gz" -o google-cloud-sdk.tar.gz; \ fi && \ tar -xzf google-cloud-sdk.tar.gz && \ ./google-cloud-sdk/install.sh -q && \ From e07e2d15f137b3c1df102aa7fb2cfefc66f69e78 Mon Sep 17 00:00:00 2001 From: Dmitry Smirnov Date: Thu, 12 Feb 2026 18:49:09 +0300 Subject: [PATCH 2/2] update docs --- docs/authorization.md | 43 ++++++++++++++++++++++---- docs/runtime/config.md | 64 +++++++++++++++++++++++++++++++++++---- docs/runtime/services.md | 65 ++++++++++++++++++++++++++++++---------- 3 files changed, 147 insertions(+), 25 deletions(-) diff --git a/docs/authorization.md b/docs/authorization.md index d9e48a9..b6b4e28 100644 --- a/docs/authorization.md +++ b/docs/authorization.md @@ -15,6 +15,8 @@ Use this when you need to: - Credentials can be provided via env vars. - Secrets can be JSON, Base64, or file paths. +- Secret references are resolved from provider paths in `worker.yaml` and matching runtime env vars. +- Authorization cleanup is controlled by `ACTORS_CLEANUP` (enabled by default). ## Examples @@ -30,17 +32,17 @@ Use this when you need to: ```json { - "client_id": "CLIENT_ID", - "client_secret": "CLIENT_SECRET", - "tenant_id": "TENANT_ID", - "subscription_id": "SUBSCRIPTION_ID" + "clientId": "CLIENT_ID", + "clientSecret": "CLIENT_SECRET", + "tenantId": "TENANT_ID", + "subscriptionId": "SUBSCRIPTION_ID" } ``` ### Base64 Format ```bash -echo -n '{"client_id":"CLIENT_ID","client_secret":"CLIENT_SECRET","tenant_id":"TENANT_ID","subscription_id":"SUBSCRIPTION_ID"}' | base64 +echo -n '{"clientId":"CLIENT_ID","clientSecret":"CLIENT_SECRET","tenantId":"TENANT_ID","subscriptionId":"SUBSCRIPTION_ID"}' | base64 ``` ### File Path @@ -49,10 +51,41 @@ echo -n '{"client_id":"CLIENT_ID","client_secret":"CLIENT_SECRET","tenant_id":"T AZURE_CREDS="/path/to/azure_credentials.json" ``` +### Provider-Specific Credential Keys + +- Azure (`AZURE_CREDS`): `clientId`, `clientSecret`, `tenantId`, `subscriptionId` +- AWS (`AWS_CREDS`): `AccessKeyId`, `SecretAccessKey`, optional `SessionToken` +- GCP (`GCP_CREDS`): standard GCP credential JSON (service account or other `gcloud --cred-file` compatible JSON) + +### Security Scenario: Long-Lived Credentials + +Example concern: +- A static service principal secret is stored in CI and reused for months. +- If leaked, an attacker can keep resolving secrets from the same vault scope until rotation. + +How worker design can mitigate: +- Fetch only referenced secrets at startup (for example `azure//`). +- Remove local auth artifacts after setup when `ACTORS_CLEANUP=true`. +- Override secret references per environment at deploy time for safer rotation workflows. + +How worker design can exacerbate: +- Resolved secrets are exported to process environment and can live for the container lifetime. +- Services can leak secrets if scripts print env vars or run with verbose shell tracing. +- A single broad credential can unlock multiple vault scopes in one worker instance. + +### Recommended Credential Posture + +- Prefer short-lived credentials or federation-based identity flows over long-lived static secrets. +- Grant least-privilege access to only the required secret scopes. +- Rotate provider credentials and secret values regularly. +- Split high-trust workloads into separate worker deployments when hard isolation is required. + ## Common Pitfalls - Using relative credential paths in production. - Storing secrets in version control. +- Using long-lived provider credentials with broad access scope. +- Reusing one credential principal for unrelated services that require isolation. ## Related Docs diff --git a/docs/runtime/config.md b/docs/runtime/config.md index 1c302c5..c0c42af 100644 --- a/docs/runtime/config.md +++ b/docs/runtime/config.md @@ -16,7 +16,11 @@ Use this when you need to: - Runtime-only config: `/home/udx/.config/worker/worker.yaml`. - Deployment env vars override `worker.yaml` values. -- Secret references use `provider/vault/secret` format. +- Secret references use `provider//` format. +- Provider reference formats: + - `azure//` + - `gcp//` + - `aws//` ## Examples @@ -30,11 +34,25 @@ config: AZURE_CLIENT_ID: "12345678-1234-1234-1234-1234567890ab" AWS_REGION: "us-west-2" secrets: - DB_PASSWORD: "aws/prod/db_password" + DB_PASSWORD: "aws/db-password/us-west-2" API_KEY: "azure/kv-prod/api-key" ``` -### Secret References in Env +### Static Secret Injection (`API_KEY`) and External Secret Resolution (`DB_PASSWORD`) + +```yaml +kind: workerConfig +version: udx.io/worker-v1/config +config: + env: + API_KEY: "dev-only-static-key" + secrets: + DB_PASSWORD: "azure/kv-prod/db-password" +``` + +`API_KEY` is injected as-is. `DB_PASSWORD` is resolved from the provider and then exported as an environment variable. + +### Secret References in `config.env` ```yaml config: @@ -44,11 +62,47 @@ config: LOG_LEVEL: "info" ``` +If an `env` value matches a secret reference format, the worker resolves it at startup. + +### Separate Secret Scopes for Different Services + +Use separate variable names in `worker.yaml`, then consume the right variable in each service: + +```yaml +# worker.yaml +kind: workerConfig +version: udx.io/worker-v1/config +config: + secrets: + SERVICE_A_DB_PASSWORD: "azure/kv-service-a/db-password" + SERVICE_B_DB_PASSWORD: "azure/kv-service-b/db-password" +``` + +```yaml +# services.yaml +kind: workerService +version: udx.io/worker-v1/service +services: + - name: "serviceA" + command: "bash -lc 'exec /home/udx/bin/service_a.sh'" + envs: + - "SERVICE_NAME=serviceA" + + - name: "serviceB" + command: "bash -lc 'exec /home/udx/bin/service_b.sh'" + envs: + - "SERVICE_NAME=serviceB" +``` + +`serviceA` should read `SERVICE_A_DB_PASSWORD`, and `serviceB` should read `SERVICE_B_DB_PASSWORD`. +For strict isolation boundaries, run separate worker instances with separate identities. + ### Runtime Environment and Precedence 1. **Deployment environment variables** (highest priority) -2. `worker.yaml` `config.secrets` -3. `worker.yaml` `config.env` +2. Deployment environment variables containing secret references (resolved at startup) +3. `worker.yaml` `config.secrets` +4. `worker.yaml` `config.env` Example override: diff --git a/docs/runtime/services.md b/docs/runtime/services.md index 1c69d28..2fae3e0 100644 --- a/docs/runtime/services.md +++ b/docs/runtime/services.md @@ -15,6 +15,7 @@ Use this when you need to: - Runtime-only: it lives inside the container at `/home/udx/.config/worker/`. - Image selection happens at deployment time (see `docs/deploy/README.md`). +- Each service is configured with a single `command` string (there is no `args` field in `services.yaml`). ## Examples @@ -40,7 +41,9 @@ kind: workerService version: udx.io/worker-v1/service services: - name: "logger" - command: "bash -c 'echo "[startup] logger"; while true; do echo "[tick] $(date)"; sleep 5; done'" + command: >- + bash -lc 'echo "[startup] logger"; + while true; do echo "[tick] $(date)"; sleep 5; done' autostart: true autorestart: true ``` @@ -48,42 +51,74 @@ services: Then view output: ```bash -worker service logs logger +worker service logs logger --tail 100 --follow +worker service errors logger --tail 100 --follow ``` Example scripts: `src/examples/simple-service/` -### Multiple Services +### Two Independent Services (Concurrent) ```yaml kind: workerService version: udx.io/worker-v1/service services: - - name: "api-server" - command: "npm start" + - name: "serviceA" + command: >- + bash -lc 'echo "starting $SERVICE_NAME"; exec /home/udx/bin/service_a.sh' autostart: true autorestart: true - stopasgroup: true - killasgroup: true envs: - - "PORT=3000" - - "NODE_ENV=production" + - "SERVICE_NAME=serviceA" + - "LOG_LEVEL=info" - - name: "worker-queue" - command: "python worker.py" + - name: "serviceB" + command: >- + bash -lc 'echo "starting $SERVICE_NAME"; exec /home/udx/bin/service_b.sh' autostart: true + autorestart: true envs: - - "QUEUE_URL=redis://localhost:6379" + - "SERVICE_NAME=serviceB" + - "LOG_LEVEL=warn" +``` + +### Passing Command-Line Arguments to a Script - - name: "monitoring" - command: "./monitor.sh" - ignore: true +```yaml +kind: workerService +version: udx.io/worker-v1/service +services: + - name: "job-runner" + command: >- + /home/udx/bin/job-runner.sh + --config-path=/etc/app/config.json + --mode=sync + --retry=3 + autostart: true + autorestart: true +``` + +### Reading Environment Variables in the Executed Command + +```yaml +kind: workerService +version: udx.io/worker-v1/service +services: + - name: "print-service-name" + command: >- + bash -lc 'echo "SERVICE_NAME=$SERVICE_NAME"; exec /home/udx/bin/start.sh' + autostart: true + autorestart: true + envs: + - "SERVICE_NAME=worker-api" ``` ## Common Pitfalls - Using `services.yaml` to select the image (use `deploy.yml` instead). - Forgetting to mount `services.yaml` into the container. +- Expecting an `args` field in `services.yaml` (put arguments directly in `command`). +- Putting provider references (for example `azure/...`) in `services.yaml` `envs`. ## Related Docs