or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

admin.mdadvanced.mdclient-server.mdcredentials-security.mderrors-status.mdhealth.mdindex.mdinterceptors.mdload-balancing.mdmetadata-context.mdname-resolution.mdobservability.mdreflection.mdstreaming.mdtesting.mdxds.md
tile.json

admin.mddocs/

Admin Services

This document covers administrative services in gRPC-Go, including channelz and CSDS (Client Status Discovery Service).

Overview

The admin package provides a convenient method for registering administrative services:

  • Channelz: Real-time debugging of channels and connections
  • CSDS: Client status discovery for xDS configuration
import "google.golang.org/grpc/admin"

Registration

Basic Registration

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/admin"
)

server := grpc.NewServer()

// Register admin services
cleanup, err := admin.Register(server)
if err != nil {
    log.Fatalf("failed to register admin services: %v", err)
}

// Register your services
pb.RegisterMyServiceServer(server, &myServiceImpl{})

// Serve
lis, _ := net.Listen("tcp", ":50051")
go server.Serve(lis)

// Cleanup when done
defer cleanup()
defer server.Stop()

Admin Service Types

// Register registers the following services:
// - Channelz
// - CSDS (if server is *grpc.Server or *xds.GRPCServer)
func Register(s grpc.ServiceRegistrar) (cleanup func(), _ error)

Channelz Service

Overview

Channelz provides runtime debugging information about gRPC channels, subchannels, and sockets.

Querying Channelz

# Get top-level channels
grpcurl -plaintext localhost:50051 grpc.channelz.v1.Channelz.GetTopChannels

# Get servers
grpcurl -plaintext localhost:50051 grpc.channelz.v1.Channelz.GetServers

# Get specific channel
grpcurl -plaintext -d '{"channel_id": 1}' localhost:50051 grpc.channelz.v1.Channelz.GetChannel

# Get subchannel
grpcurl -plaintext -d '{"subchannel_id": 1}' localhost:50051 grpc.channelz.v1.Channelz.GetSubchannel

# Get socket
grpcurl -plaintext -d '{"socket_id": 1}' localhost:50051 grpc.channelz.v1.Channelz.GetSocket

Channelz Information

Channelz provides:

  • Channel connectivity state
  • Number of calls started/succeeded/failed
  • Last call started timestamp
  • Target address
  • Load balancing policy
  • Subchannel information
  • Socket details (local/remote addresses, security, etc.)

Programmatic Access

import (
    "context"
    "google.golang.org/grpc"
    channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1"
)

conn, err := grpc.NewClient("localhost:50051",
    grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

client := channelzpb.NewChannelzClient(conn)

// Get top channels
resp, err := client.GetTopChannels(context.Background(),
    &channelzpb.GetTopChannelsRequest{
        StartChannelId: 0,
    })
if err != nil {
    log.Fatal(err)
}

for _, ch := range resp.Channel {
    fmt.Printf("Channel %d: %s\n", ch.Ref.ChannelId, ch.Ref.Name)
    fmt.Printf("  State: %v\n", ch.Data.State.State)
    fmt.Printf("  Target: %s\n", ch.Data.Target)
    fmt.Printf("  Calls started: %d\n", ch.Data.CallsStarted)
    fmt.Printf("  Calls succeeded: %d\n", ch.Data.CallsSucceeded)
    fmt.Printf("  Calls failed: %d\n", ch.Data.CallsFailed)
}

CSDS (Client Status Discovery Service)

Overview

CSDS allows querying xDS configuration status from gRPC clients and servers.

Querying CSDS

# Get client config status
grpcurl -plaintext localhost:50051 envoy.service.status.v3.ClientStatusDiscoveryService.FetchClientStatus

CSDS Information

CSDS provides:

  • xDS configuration status
  • Node information
  • Generic xDS config for all resources (LDS, RDS, CDS, EDS)
  • Resource versions
  • Update timestamps
  • Error details if configuration failed

Programmatic Access

import (
    "context"
    "google.golang.org/grpc"
    csdspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
)

conn, err := grpc.NewClient("localhost:50051",
    grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

client := csdspb.NewClientStatusDiscoveryServiceClient(conn)

// Fetch client status
resp, err := client.FetchClientStatus(context.Background(),
    &csdspb.ClientStatusRequest{})
if err != nil {
    log.Fatal(err)
}

for _, config := range resp.Config {
    fmt.Printf("Node: %s\n", config.Node.Id)
    for _, xdsConfig := range config.GenericXdsConfigs {
        fmt.Printf("  Type: %s\n", xdsConfig.TypeUrl)
        fmt.Printf("  Version: %s\n", xdsConfig.VersionInfo)
        fmt.Printf("  Status: %v\n", xdsConfig.ClientStatus)
    }
}

Best Practices

Security

  1. Restrict access: Admin services should not be publicly exposed
  2. Separate port: Consider running admin services on separate port
  3. Authentication: Use interceptors to restrict admin service access
  4. TLS: Always use TLS for production admin endpoints

Usage

  1. Enable in development: Very useful for debugging
  2. Production use: Carefully consider security implications
  3. Monitoring integration: Integrate channelz data with monitoring systems
  4. Resource usage: Monitor memory usage of channelz data

Example with Separate Port

import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/admin"
)

// Main server
mainServer := grpc.NewServer()
pb.RegisterMyServiceServer(mainServer, &myServiceImpl{})

// Admin server on separate port
adminServer := grpc.NewServer()
cleanup, err := admin.Register(adminServer)
if err != nil {
    log.Fatal(err)
}
defer cleanup()

// Start both servers
mainLis, _ := net.Listen("tcp", ":50051")
adminLis, _ := net.Listen("tcp", ":50052")

go mainServer.Serve(mainLis)
go adminServer.Serve(adminLis)

// Wait for shutdown
<-done

mainServer.GracefulStop()
adminServer.GracefulStop()

Example with Authentication

import (
    "context"
    "strings"
    "google.golang.org/grpc"
    "google.golang.org/grpc/admin"
    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/metadata"
    "google.golang.org/grpc/status"
)

func adminAuthInterceptor(
    ctx context.Context,
    req any,
    info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler,
) (any, error) {
    // Check if this is an admin service call
    if strings.HasPrefix(info.FullMethod, "/grpc.channelz.") ||
       strings.HasPrefix(info.FullMethod, "/envoy.service.status.") {
        md, ok := metadata.FromIncomingContext(ctx)
        if !ok {
            return nil, status.Error(codes.Unauthenticated, "missing metadata")
        }

        token := md.Get("admin-token")
        if len(token) == 0 || token[0] != "secret" {
            return nil, status.Error(codes.PermissionDenied, "invalid token")
        }
    }

    return handler(ctx, req)
}

server := grpc.NewServer(
    grpc.ChainUnaryInterceptor(adminAuthInterceptor))

admin.Register(server)

Testing

import (
    "testing"
    "google.golang.org/grpc"
    "google.golang.org/grpc/admin"
    "google.golang.org/grpc/admin/test"
    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/credentials/insecure"
    "google.golang.org/grpc/test/bufconn"
)

func TestAdminServices(t *testing.T) {
    lis := bufconn.Listen(1024 * 1024)
    server := grpc.NewServer()
    defer server.Stop()

    cleanup, err := admin.Register(server)
    if err != nil {
        t.Fatal(err)
    }
    defer cleanup()

    go server.Serve(lis)

    conn, err := grpc.NewClient("bufnet",
        grpc.WithContextDialer(func(ctx context.Context, s string) (net.Conn, error) {
            return lis.DialContext(ctx)
        }),
        grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        t.Fatal(err)
    }
    defer conn.Close()

    // Test admin services
    test.RunRegisterTests(t, test.ExpectedStatusCodes{
        ChannelzCode: codes.OK,
        CSDSCode:     codes.OK,
    })
}