mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-16 12:15:10 +00:00
feat(v5): add server reconciliation and canvas APIs
Split V5 dashboard behavior into domain controllers and policies, add agent token rotation/revocation, status reconciliation jobs, ingress firewall syncing, and canvas connection APIs. Add migrations for V5 status tracking, server capabilities, resource connection aliases, and revoked agent tokens.
This commit is contained in:
1 parent
df854feee8
commit
6ae45684f9
147 files changed
+22444
-10407
No files matched your search
@@ -5,4 +5,21 @@ return [
|
||||
'coold_version' => env('COOLIFY_COOLD_VERSION', 'nightly'),
|
||||
'corrosion_version' => env('COOLIFY_CORROSION_VERSION', 'v1.0.0'),
|
||||
'dev_ssh_user' => env('COOLIFY_CLI_SSH_USER', 'coolify'),
|
||||
'flux_url' => env('COOLIFY_COOLD_FLUX_URL', env('COOLIFY_COOLD_VM_FLUX_URL')),
|
||||
'flux_host_jwt_path' => env('COOLIFY_COOLD_HOST_JWT_PATH', '/etc/coolify/host-jwt'),
|
||||
|
||||
/*
|
||||
* When false (the default), v5 server hosts/node addresses may not point at
|
||||
* private or reserved IP ranges (loopback, link-local, RFC 1918, CGNAT is
|
||||
* still allowed as it is the WireGuard mesh space). This blocks a team
|
||||
* member from adding a server that targets the Coolify host's internal
|
||||
* network and abusing the synchronous SSH connectivity check to probe it.
|
||||
*
|
||||
* Self-hosters running Coolify on a private LAN can opt back in by setting
|
||||
* COOLIFY_ALLOW_PRIVATE_SERVER_IPS=true.
|
||||
*/
|
||||
'allow_private_server_ips' => filter_var(
|
||||
env('COOLIFY_ALLOW_PRIVATE_SERVER_IPS', false),
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
];
|
||||
+100
@@ -7,5 +7,105 @@ return [
|
||||
'health_timeout_seconds' => (float) env('COOLIFY_FLUX_HEALTH_TIMEOUT_SECONDS', 1.0),
|
||||
'connection_timeout_seconds' => (float) env('COOLIFY_FLUX_CONNECTION_TIMEOUT_SECONDS', 1.0),
|
||||
'dispatch_timeout_seconds' => (float) env('COOLIFY_FLUX_DISPATCH_TIMEOUT_SECONDS', 35.0),
|
||||
'bootstrap_host_connection_timeout_seconds' => (int) env('COOLIFY_FLUX_BOOTSTRAP_HOST_CONNECTION_TIMEOUT_SECONDS', 30),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Host agent (coold) token capabilities
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The EXACT set of primitive capability strings coold advertises to flux on
|
||||
| connect (coold/coold/src/grpc/client.rs, `primitive_capabilities`). Minting
|
||||
| these explicit strings — instead of the `host-agent:default` wildcard
|
||||
| profile — means the token no longer relies on flux's
|
||||
| `capability_profile_authorizes_all` bypass. flux INTERSECTS the jwt `caps`
|
||||
| with coold's advertised set, so as long as this list matches coold's
|
||||
| advertised primitives the host retains exactly the same effective power.
|
||||
|
|
||||
| SAFETY: keep this list byte-for-byte in sync with coold's
|
||||
| `primitive_capabilities()`. A string here that coold does not advertise is
|
||||
| silently dropped by flux's intersection; a verb coold needs that is missing
|
||||
| here means the host loses that ability.
|
||||
|
|
||||
| `host.jwt.set` authorizes RPC-delivered host-JWT rotation (the token can
|
||||
| authorize its own replacement over the live stream; Laravel is the root of
|
||||
| trust that holds the signing key).
|
||||
*/
|
||||
'host_capabilities' => [
|
||||
'images.pull',
|
||||
'images.list',
|
||||
'images.delete',
|
||||
'containers.create',
|
||||
'containers.start',
|
||||
'containers.stop',
|
||||
'containers.restart',
|
||||
'containers.delete',
|
||||
'containers.inspect',
|
||||
'containers.list',
|
||||
'containers.logs',
|
||||
'containers.exec',
|
||||
'containers.healthcheck.run',
|
||||
'ingress.apply',
|
||||
'ingress.stop',
|
||||
'firewall.allow',
|
||||
'firewall.revoke',
|
||||
'firewall.list',
|
||||
'firewall.reconcile',
|
||||
'coold.logs',
|
||||
'corrosion.tables',
|
||||
'host.jwt.set',
|
||||
],
|
||||
|
||||
/*
|
||||
| Emergency escape hatch: when set (e.g. to `host-agent:default`), minted
|
||||
| host tokens carry ONLY this single capability profile instead of the
|
||||
| explicit list above. This re-enables flux's wildcard bypass and is meant
|
||||
| purely for rollback without a code change if the explicit list ever drifts
|
||||
| from coold's advertised set and breaks the data plane. Leave NULL in
|
||||
| production so tokens are explicitly scoped.
|
||||
*/
|
||||
'host_capability_profile' => env('COOLIFY_FLUX_HOST_CAPABILITY_PROFILE'),
|
||||
|
||||
/*
|
||||
| Host JWT lifetime and rotation.
|
||||
|
|
||||
| `host_token_ttl` is the token `exp` window (default 1h) — the maximum time
|
||||
| a leaked/undetected token stays valid if BOTH rotation and revocation fail.
|
||||
| Keep this at or below flux's `COOLIFY_FLUX_MAX_TOKEN_LIFETIME_SECS`
|
||||
| default (3600), otherwise flux rejects coold streams at connect.
|
||||
| `host_token_refresh_threshold` is the remaining-lifetime below which the
|
||||
| rotation job re-mints and re-delivers a fresh token (default 30m).
|
||||
| Keep the threshold below the TTL.
|
||||
*/
|
||||
'host_token_ttl' => (int) env('COOLIFY_FLUX_HOST_TOKEN_TTL', 3600),
|
||||
'host_token_refresh_threshold' => (int) env('COOLIFY_FLUX_HOST_TOKEN_REFRESH_THRESHOLD', 1800),
|
||||
|
||||
/*
|
||||
| JWT header `kid` minted into host tokens. flux selects the verification key
|
||||
| by this id (single default key today; a per-cluster keys directory can map
|
||||
| `kid = cluster-<id>` to `<kid>.pub` for per-tenant signing keys later).
|
||||
*/
|
||||
'jwt_kid' => env('COOLIFY_FLUX_JWT_KID', 'flux-default'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Inbound flux -> Laravel API token(s)
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| flux authenticates to Laravel's internal status-ingest endpoint with a
|
||||
| bearer token. `laravel_api_tokens` accepts SEVERAL tokens at once so an
|
||||
| operator can rotate with zero downtime:
|
||||
| 1. add the new token alongside the old:
|
||||
| COOLIFY_FLUX_LARAVEL_API_TOKENS=<old>,<new>
|
||||
| then `php artisan config:clear`
|
||||
| 2. cut every flux instance over to <new>
|
||||
| 3. drop <old> from the list and `config:clear` again
|
||||
| Generate tokens with `openssl rand -hex 32`. The single `laravel_api_token`
|
||||
| remains as a fallback so existing single-token installs keep working.
|
||||
*/
|
||||
'laravel_api_token' => env('COOLIFY_FLUX_LARAVEL_API_TOKEN'),
|
||||
'laravel_api_tokens' => array_values(array_filter(array_map(
|
||||
'trim',
|
||||
explode(',', (string) env('COOLIFY_FLUX_LARAVEL_API_TOKENS', ''))
|
||||
))),
|
||||
];
|
||||
+28
-1
@@ -192,6 +192,24 @@ return [
|
||||
'sleep' => 3,
|
||||
'timeout' => env('HORIZON_TIMEOUT', 36000),
|
||||
],
|
||||
|
||||
// Dedicated low-priority pool for the v5 reconcile + host-token rotation
|
||||
// jobs (queue `v5-reconcile`, set via onQueue()). Isolated from the
|
||||
// user-facing high/default deploy pool so a starved rotation cannot let
|
||||
// host tokens drift to expiry, and so the 5-minute fleet fan-out never
|
||||
// blocks deploys.
|
||||
'v5reconcile' => [
|
||||
'connection' => 'redis',
|
||||
'balance' => env('HORIZON_V5_RECONCILE_BALANCE', 'false'),
|
||||
'queue' => 'v5-reconcile',
|
||||
'maxTime' => env('HORIZON_V5_RECONCILE_MAX_TIME', 0),
|
||||
'maxJobs' => 200,
|
||||
'memory' => 128,
|
||||
'tries' => 1,
|
||||
'nice' => 10,
|
||||
'sleep' => 3,
|
||||
'timeout' => env('HORIZON_V5_RECONCILE_TIMEOUT', 300),
|
||||
],
|
||||
],
|
||||
|
||||
'environments' => [
|
||||
@@ -203,7 +221,11 @@ return [
|
||||
'balanceMaxShift' => env('HORIZON_BALANCE_MAX_SHIFT', 1),
|
||||
'balanceCooldown' => env('HORIZON_BALANCE_COOLDOWN', 1),
|
||||
],
|
||||
|
||||
'v5reconcile' => [
|
||||
'autoScalingStrategy' => 'size',
|
||||
'minProcesses' => env('HORIZON_V5_RECONCILE_MIN_PROCESSES', 1),
|
||||
'maxProcesses' => env('HORIZON_V5_RECONCILE_MAX_PROCESSES', 2),
|
||||
],
|
||||
],
|
||||
'local' => [
|
||||
's6' => [
|
||||
@@ -213,6 +235,11 @@ return [
|
||||
'balanceMaxShift' => env('HORIZON_BALANCE_MAX_SHIFT', 1),
|
||||
'balanceCooldown' => env('HORIZON_BALANCE_COOLDOWN', 1),
|
||||
],
|
||||
'v5reconcile' => [
|
||||
'autoScalingStrategy' => 'size',
|
||||
'minProcesses' => env('HORIZON_V5_RECONCILE_MIN_PROCESSES', 1),
|
||||
'maxProcesses' => env('HORIZON_V5_RECONCILE_MAX_PROCESSES', 1),
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
Reference in new issue
Block a user