tacacs

module
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2026 License: MIT

README

tacacs

CI Codecov Go Reference Go Report Card

A commercial-grade Go implementation of the TACACS+ protocol suite.

tacacs is a pure-Go library that implements the full family of TACACS specifications published by the IETF, together with a tacacs-cli command-line tool for interoperability testing:

RFC Title Role
RFC 1492 An Access Control Protocol, Sometimes Called TACACS original TACACS (legacy)
RFC 8907 The TACACS+ Protocol base protocol
RFC 9887 TACACS+ over TLS 1.3 secure transport
RFC 9950 A YANG Data Model for TACACS+ configuration model

Features

  • Authentication (ASCII, PAP, CHAP, MS-CHAP, MS-CHAPv2), authorization and accounting (start / stop / watchdog) per RFC 8907.
  • Predefined attribute-value pairs, organized by vendor: avp.go holds the pairs shared by all vendors (RFC 8907 §6/§8.3 base set plus the Cisco & Huawei common traditional pairs, and the disconnect-cause dual naming), avp_cisco.go the full Cisco IOS TACACS+ AV pair reference, avp_huawei.go the HWTACACS rate/tunnel/ftp pairs, avp_juniper.go the Junos exec attributes and avp_paloalto.go the PAN-OS administrator VSAs; disconnect-cause codes are enumerated by DiscCause and DiscCauseExt, with both hyphenated (disc-cause) and underscore (disc_cause) spellings for cross-vendor interop.
  • MD5-based body obfuscation (RFC 8907 §4.5) and TLS 1.3 transport (RFC 9887), which obsoletes obfuscation over TLS.
  • A YANG-aligned configuration model (RFC 9950) loadable from YAML and JSON.
  • The original TACACS protocol (RFC 1492) in both its TCP (ASCII) and UDP (simple / extended) encodings.
  • Multi-NAS deployments: per-NAS shared secrets via DNS or prefix-based SecretProvider, and PROXY protocol v1 (text) and v2 (binary) auto- detection so the server sees the real client address behind a Layer 4 load balancer (HAProxy, Envoy, AWS NLB, Cloudflare Spectrum).
  • DoS hardening: idle/read timeouts, fuzz-tested parsers, session-TTL sweeper, and strict flag-policy enforcement.
  • Pluggable AAA backends: PAM, LDAP, and HTTP authenticators in cmd/tacacs-cli/aaa; bring-your-own via the server.Handler interface.
  • Observability: Prometheus metrics (AAA latency, status histograms, active sessions) and structured audit logging via log/slog.
  • A dependency-free core with an injectable log/slog-compatible logger; tacacs-cli uses cobra, viper and logrus.

Status: the protocol core, transport, AAA backends and CLI are complete and covered by fuzz targets, race-tested unit/integration tests and a cross-implementation interop suite (in the separate interop/ module) against tacquito. See docs/operations.md for production deployment guidance and docs/load-test.md for measured throughput.

Installation

go get github.com/wxccs/tacacs

Requires Go 1.26 or later.

Quick start

Client
import (
    "context"
    "github.com/wxccs/tacacs/client"
    "github.com/wxccs/tacacs/transport"
    "github.com/wxccs/tacacs/types"
)

func authenticate() error {
    conn, err := transport.Dial(context.Background(), "tcp", "tacacs.example.com:49",
        []byte("sharedsecret"))
    if err != nil {
        return err
    }
    defer conn.Close()

    c, err := client.New(conn)
    if err != nil {
        return err
    }
    reply, err := c.Authenticate(context.Background(), client.AuthenRequest{
        Action: types.AuthenLogin, Type: types.AuthenTypePAP, Service: types.AuthenServiceLogin,
        User: "alice", Data: []byte("password"),
    }, nil)
    if err != nil {
        return err
    }
    // reply.Status == types.AuthenStatusPass on success.
    return nil
}

For TLS 1.3 (RFC 9887), use transport.DialTLS with a transport.TLSConfig instead of transport.Dial.

Server

Implement the server.Handler interface and serve connections:

import (
    "context"
    "github.com/wxccs/tacacs/server"
    "github.com/wxccs/tacacs/transport"
    "github.com/wxccs/tacacs/types"
)

type myHandler struct{}

func (myHandler) Authenticate(ctx context.Context, ac server.AuthenContext, cont *server.AuthenContinue) (server.AuthenDecision, error) {
    // ...verify credentials...
    return server.AuthenDecision{Status: types.AuthenStatusPass}, nil
}
func (myHandler) Authorize(ctx context.Context, ac server.AuthorContext) (server.AuthorDecision, error) {
    return server.AuthenDecision{Status: types.AuthorStatusPassAdd}, nil
}
func (myHandler) Account(ctx context.Context, ac server.AcctContext) (server.AcctDecision, error) {
    return server.AcctDecision{Status: types.AcctStatusSuccess}, nil
}

// ln is a net.Listener (use transport.ListenTLS for TLS 1.3).
srv := server.New(server.Config{Handler: myHandler{}, Secret: []byte("sharedsecret"), Mode: transport.ModeLegacy})
for {
    c, _ := ln.Accept()
    conn := transport.Accept(c, transport.ModeLegacy, []byte("sharedsecret"))
    go srv.ServeConn(context.Background(), conn)
}
Configuration (RFC 9950)

Load a server list from YAML or JSON:

import "github.com/wxccs/tacacs/yang"

cfg, err := yang.Load("tacacs.yaml")
// cfg.Servers is the unified, ordered server list.

See docs/examples/ for shared-secret and TLS example configurations matching the RFC 9950 appendices.

Command-line tool
# Run the test server
tacacs-cli server --listen 127.0.0.1 --port 49 --secret testkey

# Authenticate (client)
tacacs-cli auth --server 127.0.0.1 --port 49 --secret testkey \
    --username admin --password admin123 --type pap --output json

# Authorize a command
tacacs-cli authz --server 127.0.0.1 --port 49 --secret testkey \
    --username admin --service shell --cmd "show version"

# Accounting
tacacs-cli acct --server 127.0.0.1 --port 49 --secret testkey \
    --username admin --action start

For low-level packet construction and inspection, the packet, crypto, types and errors packages are usable directly.

Project layout

.
├── errors/          typed sentinel errors
├── types/           protocol constants, Logger interface, argument codec
├── packet/          header and body marshalling (RFC 8907)
├── crypto/           MD5 pseudo-pad obfuscation (RFC 8907 §4.5)
├── protocol/        authentication/authorization/accounting state machines
├── transport/       TCP and TLS 1.3 transports (RFC 9887)
├── yang/            RFC 9950 configuration model
├── client/          high-level client API
├── server/          server-side handlers
├── legacy/          RFC 1492 original TACACS
├── cmd/tacacs-cli/  command-line tool
├── interop/         separate Go module: cross-implementation tests vs tacquito
└── docs/            examples, RFC texts, operations & load-test guides

Development

make tidy        # go mod tidy
make fmt         # gofmt
make vet         # go vet
make test        # unit + integration tests
make cover       # coverage report (target >= 90%)

See CONTRIBUTING.md for the code and logging conventions, docs/operations.md for production deployment (auth backends, metrics, capacity, shutdown, multi-NAS), and docs/load-test.md for measured throughput and sizing guidance.

License

Copyright (c) 2026 Daniel Wu

This library is licensed under the MIT License. See LICENSE for the full text.

Third-party dependencies and their license terms are documented in THIRD_PARTY_LICENSES.md.

Directories

Path Synopsis
Package client provides a high-level TACACS+ client that drives complete authentication, authorization and accounting exchanges over a transport.Conn.
Package client provides a high-level TACACS+ client that drives complete authentication, authorization and accounting exchanges over a transport.Conn.
cmd
tacacs-cli command
tacacs-cli/aaa
Package aaa provides production-grade AAA backend components for the tacacs-cli server: a bcrypt-backed Authenticator, a regex-based Authorizer, and durable Accounters (file and syslog).
Package aaa provides production-grade AAA backend components for the tacacs-cli server: a bcrypt-backed Authenticator, a regex-based Authorizer, and durable Accounters (file and syslog).
tacacs-cli/metrics/prom
Package prom implements the server.Metrics interface using Prometheus counters, gauges and histograms.
Package prom implements the server.Metrics interface using Prometheus counters, gauges and histograms.
Package crypto implements the TACACS+ body obfuscation defined by RFC 8907 §4.5.
Package crypto implements the TACACS+ body obfuscation defined by RFC 8907 §4.5.
Package errors provides the sentinel and typed errors used throughout the tacacs library, together with thin wrappers around the standard library error helpers (New, Is, As, Unwrap, Join) so that callers can import a single errors package.
Package errors provides the sentinel and typed errors used throughout the tacacs library, together with thin wrappers around the standard library error helpers (New, Is, As, Unwrap, Join) so that callers can import a single errors package.
Package legacy implements the original TACACS protocol (RFC 1492), distinct from TACACS+ (RFC 8907).
Package legacy implements the original TACACS protocol (RFC 1492), distinct from TACACS+ (RFC 8907).
Package packet implements the TACACS+ packet header and body marshalling defined by RFC 8907.
Package packet implements the TACACS+ packet header and body marshalling defined by RFC 8907.
Package protocol implements the TACACS+ authentication, authorization and accounting logic on top of the packet and crypto layers (RFC 8907 §5-8, §11).
Package protocol implements the TACACS+ authentication, authorization and accounting logic on top of the packet and crypto layers (RFC 8907 §5-8, §11).
Package server implements a TACACS+ server: it accepts connections, decodes packets, drives the authentication/authorization/accounting state machines via a caller-supplied Handler, and encodes the responses.
Package server implements a TACACS+ server: it accepts connections, decodes packets, drives the authentication/authorization/accounting state machines via a caller-supplied Handler, and encodes the responses.
Package transport implements the TCP and TLS 1.3 transports for TACACS+ (RFC 8907 §4.3 and RFC 9887).
Package transport implements the TCP and TLS 1.3 transports for TACACS+ (RFC 8907 §4.3 and RFC 9887).
proxy
Package proxy implements parsing of the HAProxy PROXY protocol v1 (ASCII), used to convey the real client address through a TCP load balancer.
Package proxy implements parsing of the HAProxy PROXY protocol v1 (ASCII), used to convey the real client address through a TCP load balancer.
Package types holds the protocol constants and shared primitive types for the tacacs library: protocol versions, packet types, header flags, the authentication/authorization/accounting enumerations, privilege levels, the Argument codec, the predefined AVP name constants and constructors, the disconnect-cause enumerations, packet size limits, and the Logger interface used by the core library.
Package types holds the protocol constants and shared primitive types for the tacacs library: protocol versions, packet types, header flags, the authentication/authorization/accounting enumerations, privilege levels, the Argument codec, the predefined AVP name constants and constructors, the disconnect-cause enumerations, packet size limits, and the Logger interface used by the core library.
Package yang mirrors the ietf-system-tacacs-plus YANG data model (RFC 9950) as Go configuration structs and loads them from YAML or JSON via viper.
Package yang mirrors the ietf-system-tacacs-plus YANG data model (RFC 9950) as Go configuration structs and loads them from YAML or JSON via viper.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL