Skip to content

Self-enroll OpenZiti identity at startup via ziti-management #89

Description

@rowan-stein

User Request

Replace static identity file provisioning with runtime self-enrollment. The Gateway should call ziti-management.RequestServiceIdentity() at startup to obtain an enrolled OpenZiti identity, and periodically extend the lease via ExtendIdentityLease().

See Service Identity Self-Enrollment.

Specification

Current Behavior

The Gateway reads a pre-provisioned identity file from ZITI_IDENTITY_FILE env var and calls ziti.NewContextFromFile().

Target Behavior

  1. At startup, if OpenZiti is enabled (determined by a config flag — see below), the Gateway:
    a. Creates a gRPC client to ziti-management (already exists: zitimgmtclient.Client).
    b. Calls RequestServiceIdentity(service_type: SERVICE_TYPE_GATEWAY).
    c. Receives ziti_identity_id + identity_json (bytes).
    d. Writes identity_json to a temp file on ephemeral disk (e.g., os.CreateTemp("", "ziti-identity-*.json")).
    e. Loads the identity via ziti.NewContextFromFile(tempFile).
    f. Proceeds as before: ListenWithOptions("gateway", ...).

  2. Lease renewal: starts a background goroutine that calls ExtendIdentityLease(ziti_identity_id) every ZITI_LEASE_RENEWAL_INTERVAL (default: 2 minutes — well under the 5-minute lease TTL). On error, log and retry on next tick. On context cancellation, stop.

  3. Shutdown: temp file is cleaned up via defer os.Remove(tempFile).

Config Changes

Replace ZITI_IDENTITY_FILE with a boolean-like enablement. The identity file is no longer externally provided — it's obtained at runtime.

Env Var Default Description
ZITI_ENABLED false Enable OpenZiti self-enrollment
ZITI_MANAGEMENT_GRPC_TARGET ziti-management:50051 Already exists
ZITI_LEASE_RENEWAL_INTERVAL 2m How often to extend the lease
ZITI_SERVICE_NAME gateway Already exists

Remove ZITI_IDENTITY_FILE from the config — it's no longer used.

Changes to zitimgmtclient

The existing zitimgmtclient.Client only has ResolveIdentity. Add:

  • RequestServiceIdentity(ctx, serviceType) (zitiIdentityID string, identityJSON []byte, error)
  • ExtendIdentityLease(ctx, zitiIdentityID string) error

This requires regenerating the proto stubs from the updated BSR (which now includes the new RPCs).

Changes to main.go

The OpenZiti setup block (currently gated on config.ZitiIdentityFile != "") should be replaced with a self-enrollment flow gated on config.ZitiEnabled:

if config.ZitiEnabled {
    // 1. Request identity from ziti-management
    zitiIdentityID, identityJSON, err := zitiMgmtClient.RequestServiceIdentity(ctx, SERVICE_TYPE_GATEWAY)
    
    // 2. Write to temp file
    tmpFile, err := os.CreateTemp("", "ziti-identity-*.json")
    tmpFile.Write(identityJSON)
    tmpFile.Close()
    defer os.Remove(tmpFile.Name())
    
    // 3. Load identity
    zitiContext, err := ziti.NewContextFromFile(tmpFile.Name())
    defer zitiContext.Close()
    
    // 4. Start lease renewal
    go renewLease(ctx, zitiMgmtClient, zitiIdentityID, leaseRenewalInterval)
    
    // 5. Listen (same as before)
    listener, err := zitiContext.ListenWithOptions(serviceName, ziti.DefaultListenOptions())
    go server.Serve(listener)
}

Proto Stub Regeneration

The Gateway needs to pull the updated proto from BSR to get the new RequestServiceIdentity and ExtendIdentityLease RPCs. Run buf dep update + buf generate to regenerate stubs.

Lease Renewal Function

func renewLease(ctx context.Context, client *zitimgmtclient.Client, identityID string, interval time.Duration) {
    ticker := time.NewTicker(interval)
    defer ticker.Stop()
    for {
        select {
        case <-ctx.Done():
            return
        case <-ticker.C:
            if err := client.ExtendIdentityLease(ctx, identityID); err != nil {
                log.Printf("failed to extend ziti lease: %v", err)
            }
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions