Tacacs+服务搭建与配置详解


其他文章:


简介

tac_plus是TACACS +守护程序。它为网络设备和访问服务器提供身份验证,授权和计费服务。(authentication, authorisation and accounting)

此版本是原始Cisco源代码的主要重写。主要功能包括:

  • NAS特定的主机密钥,提示,开启密码
  • 与NAS和ACL相关的组成员身份
  • 用于用户配置文件的灵活的外部后端(例如,通过PERL脚本或C;包括LDAP(包括ActiveDirectory),RADIUS和其他)
  • 连接多路复用(每个进程有多个并发NAS客户端)
  • 会话多路复用(每个连接多个并发会话,单连接
  • 可扩展,对用户,客户端或服务器无限制
  • CLI上下文感知。在撰写本文时,没有其他TACACS +守护程序。
  • 完全支持IPv4和IPv6。
  • 符合最新的TACACS +协议规范(draft 1.78)

下载和安装:

源码安装与配置示例:

wget http://www.pro-bono-publico.de/projects/src/DEVEL.tar.bz2

https://github.com/facebookarchive/tac_plus

https://networkengineering.stackexchange.com/questions/45436/how-do-you-configure-a-tacacs-tac-plus-server-on-ubuntu-16-04-that-authenticate

安装步骤:

下面的安装是在CentOS7中进行了测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
wget http://www.pro-bono-publico.de/projects/src/DEVEL.tar.bz2
bzip2 -dc DEVEL.tar.bz2 | tar xvfp -
sudo yum install rpm-build redhat-rpm-config gcc bison flex m4 pam-devel tcp_wrappers tcp_wrappers-devel
yum -y install perl-Digest-MD5
yum install perl-LDAP
cd PROJECTS
make
make install
mkdir /var/log/tac_plus
mkdir /var/log/tac_plus/access
mkdir /var/log/tac_plus/accounting
mkdir /var/log/tac_plus/authentication
mkdir /var/log/tac_plus/authorization
chmod 755 /var/log/tac_plus
cp tac_plus/extra/tac_plus.service /etc/systemd/system/

下一步需要创建配置文件:

在/usr/local/etc/mavis/sample/tac_plus.cfg为示例配置文件。可直接拷贝到/usr/local/etc/下,直接启动服务。

在这里进行手动创建配置文件:

1
2
3
4
cd /usr/local/etc
sudo touch tac_plus.cfg
sudo chmod 755 tac_plus.cfg
sudo vim tac_plus.cfg

如果是使用只使用tacacs+服务器配置文件中的用户密码进行认证,可使用如下配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
[root@localhost etc]# more tac_plus.cfg 
#!../../../sbin/tac_plus

id = spawnd {
# tacacs+默认端口为49,wireshark可将目的端口为49的tcp解析为tacacs+报文
listen = { port = 49 }
spawn = {
instances min = 1
instances max = 100
}
background = no
}

id = tac_plus {
#debug = PACKET AUTHEN AUTHOR

access log = /var/log/tac_plus/access/access.log
authorization log = /var/log/tac_plus/authorization/authorization.log
authentication log = /var/log/tac_plus/authentication/authentication.l
og
accounting log = /var/log/tac_plus/accounting/accounting.log

host = world {
address = ::/0
prompt = "Welcome\n"
key = "tacacs@123"
}

group = admin {
default service = permit
service = shell {
default command = permit
default attribute = permit
set priv-lvl = 15
}
}

group = guest {
default service = permit
enable = deny
service = shell {
default command = permit
default attribute = permit
set priv-lvl = 1
}
}

user = tacacsuser {
#使用明文密码
password = clear tacacs123
member = admin
service = shell {
default command = permit
default attribute = permit
set priv-lvl = 15
}
}

user = user1 {
#使用密文密码,密文可通过如下命令生成
#openssl passwd -crypt user123
password = crypt Ljk4p8tGXkuVw
member = admin
service = shell {
default command = permit
default attribute = permit
set priv-lvl = 15
}
}

user = readonly {
password = clear readonly
member = guest
}
}

创建完配置文件后,进行启动tacacs+服务器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost etc]# systemctl restart tac_plus
[root@localhost etc]# systemctl enable tac_plus
[root@localhost etc]# systemctl status tac_plus
● tac_plus.service - TACACS+ Service
Loaded: loaded (/etc/systemd/system/tac_plus.service; enabled; vendor pres)
Active: active (running) since Tue 2020-10-06 18:03:29 CST; 20s ago
Main PID: 13090 (tac_plus)
CGroup: /system.slice/tac_plus.service
├─13061 tac_plus: 3 connections left, dying when idle
├─13090 tac_plus: 0 connections, accepting up to 600 more
└─13091 tac_plus: 0 connections

Oct 06 18:03:29 localhost.localdomain systemd[1]: Started TACACS+ Service.
Oct 06 18:03:29 localhost.localdomain systemd[1]: Starting TACACS+ Service...
Oct 06 18:03:29 localhost.localdomain tac_plus[13090]: startup (version 202...
Oct 06 18:03:29 localhost.localdomain tac_plus[13090]: epoll event notifica...
Oct 06 18:03:29 localhost.localdomain tac_plus[13090]: bind to [::]:49 succ...
Oct 06 18:03:29 localhost.localdomain tac_plus[13091]: - Version 2020062010...
Oct 06 18:03:29 localhost.localdomain tac_plus[13091]: epoll event notifica...
Hint: Some lines were ellipsized, use -l to show in full.
[root@localhost etc]# netstat -lntp | grep 49
tcp6 0 0 :::49 :::* LISTEN

当系统开始监听49端口,则证明tacacs+服务正常安装并启动。

若需要使用LDAP等后端进行认证,可使用如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
[root@localhost etc]# more tac_plus.cfg 
#!/usr/local/sbin/tac_plus
id = spawnd {
listen = { port = 49 }
spawn = {
instances min = 1
instances max = 100
}
background = yes #开启后端认证
}
id = tac_plus {
#debug = PACKET AUTHEN AUTHOR
anonymous-enable = deny
augmented-enable = deny
date format = "%Y-%m-%d %H:%M:%S"
log separator = ","
access log = /var/log/tac_plus/access/access.log
authorization log = /var/log/tac_plus/authorization/authorization.log
authentication log = /var/log/tac_plus/authentication/authentication.log
accounting log = /var/log/tac_plus/accounting/accounting.log
mavis module = external {
setenv LDAP_SERVER_TYPE = "tacacs_schema"
setenv LDAP_HOSTS = "ldaps://xxxx"
setenv LDAP_BASE = "ou=xx,dc=xxx,dc=xx"
setenv LDAP_SCOPE = sub
setenv LDAP_FILTER = "(uid=%s)"
setenv LDAP_USER = "cn=xx,dc=xx,dc=xx"
setenv LDAP_PASSWD = ""
#Clear default setting of tacplus for AD_GROUP_PREFIX
setenv AD_GROUP_PREFIX = ""
#Setting REQUIRE_TACACS_GROUP_PREFIX to 1 will cause a NACK response if the AD account is not a member of a security group with the required prefix
setenv REQUIRE_TACACS_GROUP_PREFIX = 0
exec = /usr/local/lib/mavis/mavis_tacplus_ldap.pl
}
login backend = mavis
user backend = mavis
pap backend = mavis

host = world {
address = ::/0
prompt = "Welcome\n"
key = "tacacs@123"
}

# test group
group = test {
#Permit all services by default
default service = permit
service = shell {
default command = permit
default attribute = permit
set priv-lvl = 15
set Huawei-Exec-Privilege = 15
set Huawei-Exec-Privilege = 3
# h3c and huawei command
cmd = display {
deny version
permit .*
}
# ruijie command
cmd = show {
deny arp
permit .*
}
}
}

user = tacacsuser {
member = test
}

每次修改完配置文件,需要进行重启服务。

可以使用/usr/local/sbin/tac_plus -P /usr/local/etc/tac_plus.cfg 来检查cfg文件是否有语法错误,

可以使用如下方法来检测tac_plus到LDAP连接是否成功,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/usr/local/bin/mavistest -d -1 /usr/local/etc/tac_plus.cfg tac_plus TACPLUS SomeUserName SomeUserPassword
{mavistest debug output omitted}
Input attribute-value-pairs:
TYPE TACPLUS
TIMESTAMP mavistest-2501-1509172787-0
USER SomeUserName
PASSWORD SomeUserPassword
TACTYPE AUTH
Output attribute-value-pairs:
TYPE TACPLUS
TIMESTAMP mavistest-2501-1509172787-0
USER SomeUserName
RESULT ACK
PASSWORD SomeUserPassword
SERIAL QrWVmlId0OZADDRU/hy/pw=
DBPASSWORD SomeUserPassword
TACMEMBER [List of Active Directory security groups]
TACTYPE AUTH

注意查看RESULT,若为ACK则表示成功,如遇见其他状态,请进行LDAP的故障排查.

定义和术语

以下各章使用了一些术语,可能需要进一步说明:

  • NAC: (Netwrok Access Client)

    网络访问客户端,例如telnet连接的源主机。

  • NAS,(Network Access Server)

    网络访问服务器,例如Cisco设备或发出TACACS +身份验证和授权请求或生成TACACS +计费数据包的任何其他客户端。

  • Daemon: 一个程序,为网络提供服务以请求身份验证和授权,验证身份,授予或拒绝授权以及记录计费记录。

  • AV pairs: 作为TACACS +协议的一部分,在NAS和TACACS +守护程序之间发送的格式为attribute = value的文本字符串。

由于NAS有时被称为服务器,而守护程序也通常被称为服务器,因此在这里避免使用服务器一词,而是使用不易模糊的术语NAS和Daemon。

TACACS,XTACACS and TACACS+:

作为一个有历史价值的信息,大约有三个版本的认证协议,人们可以称为TACACS:

第一个是普通的TACACS,在思科设备中第一次提供,并已使用多年。

第二个是对第一个的扩展,通常称为扩展(Extended)的TACACS或XTACACS,是在1990年引入的。两者都是基于UDP的服务。

第三个版本是TACACS+或tac_plus,这是现在所有人都在用的版本。TACACS+基于TCP,因此不兼容任何以前版本的TACACS。

显然,至少有一个供应商实现了TACACS+,但将其称为HWTACACS。这背后可能没有技术(但可能是营销或法律)原因。文档是缺失的。

操作方式(Operation)

本节简要概述了如何运行tac_plus

在早期版本中,tac_plus不是一个独立程序,而必须由衍生(spawnd)程序调用。这已经改变,因为生成(spawnd)的功能现在是tac_plus二进制文件的一部分。但是,仍然可以使用专用的生成(spawnd)过程,更重要的是,生成(spawnd)的配置选项和文档仍然有效。

tac_plus可以使用辅助的MAVIS后端模块进行认证和授权。

命令行语法(Command line syntax):

唯一必需的参数是配置文件的路径。

1
tac_plus [ -P ] [ -d level ] [ -i child_id ] configuration-file [ id ]
  • 如果程序是在CURL支持下编译的,则配置文件可能是URL。

  • -P:请记住-P选项-所提供的配置文件在语法上必须正确,因为如果启动时出现任何解析错误,则守护程序将不会启动。

  • -d:开关启用调试。很可能不想使用它。如果需要,请阅读源码。

  • -i:仅在使用内置衍生(spawnd)功能时才使用-i选项。在这种情况下,它将为tac_plus选择配置ID,而可选的最后一个参数id则设置生成(spawnd)的配置节的ID。

信号(Signals):

主进程(即运行派生(spawnd)代码的进程)和子进程(即运行tac_plus代码)都拦截SIGHUP信号:

  • 主进程将在接收到SIGHUP后重新启动,重新读取配置文件。子进程将识别出主进程不再可用。它将继续为现有连接提供服务,并在空闲时终止。
  • 如果SIGHUP被发送到子进程,它将停止接受来自其主进程的新连接。它将继续为现有连接提供服务,并在空闲时终止。

将SIGUSR1发送到主进程将导致它放弃现有的子进程(这些子进程将仅继续为现有的连接提供服务)并启动新的子进程。

事件机制选择(Evenet mechainsm selection):

支持几种级别触发的事件机制。默认情况下,将使用最适合的你操作系统的一种。但是,可以将环境变量IO_POLL_MECHANISM设置为选择特定变量。

支持以下事件机制(按优先顺序):

  • port (Sun Solaris 10 and higher only, IO_POLL_MECHANISM=32)
  • kqueue (*BSD and Darwin only, IO_POLL_MECHANISM=1)
  • /dev/poll (Sun Solaris only, IO_POLL_MECHANISM=2)
  • epoll (Linux only, IO_POLL_MECHANISM=4)
  • poll (IO_POLL_MECHANISM=8)
  • select (IO_POLL_MECHANISM=16)

可以在顶级(top-level)配置文件中设置环境变量:

1
setenv IO_POLL_MECHANISM = 4

示例配置(Sample Configuration):

单配置文件足以配置派生(spawnd),tac_plus以及MAVIS认证和授权后端。

下面的spawnd配置接受TCP端口49和4949的连接,并将它们转发给一个tac_plus进程。tac_plus配置配置了几个用户组,定义了一个用户,并依赖MAVIS后端来获取其他用户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/local/sbin/tac_plus
id = spawnd {
listen = { port = 49 }
listen = { port = 4949 }
# see the spawnd configuration guide for further configuration options
}

id = tac_plus {
accounting log = /var/log/tac_plus/%Y/%m/%d.log
retire limit = 1000
mavis module = external {
exec = /usr/local/lib/mavis_tacplus_passwd.pl
# see the MAVIS configuration manual for more options and other modules
}
login backend = mavis

host = world {
welcome banner = "\nHitherto shalt thou come, but no further. (Job 38.11)\n\n"
key = QaWsEdRfTgY
enable 15 = clear test
address = 0.0.0.0/0
}

group = readwrite {
default service = permit
service = shell {
default command = permit
set priv-lvl = 15
}
}

group = getconfig {
default service = permit
service = shell {
set autocmd = "show run"
set priv-lvl = 15
}
}

user = marc {
login = crypt $1$xxxxxxxx$hDZPHghXe8XvoHeFdqUwm/
member = readwrite@world
member = getconfig@192.168.0.0/16
}
}

域的示例配置( Sample Configuration with Realms):

这是一个更复杂的示例,承认大多数人更喜欢查看示例配置,而不是实际阅读文档。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
syslog default = deny

id = spawnd {
# Really, have a look at the spawnd configuration. There are
# lots of useful options.

listen = {
port = 4949
}

listen = {
port = 4950 realm = core
}
}

id = tac_plus {
client realm = adminRealm # Could specify these
aaa realm = local # at host level, too.
dns reverse-lookup = no

realm = adminRealm {
host = myPCs {
address = 192.0.2.8,192.0.2.24/29
}
}

realm = customerRealm {
dns reverse-lookup = yes
host = customer {
address = 172.16.0.0/12
}
}

# This will be placed in the "default" realm
host = cpeRouters {
address = 0.0.0.0/0
key = myKey
welcome banner = "Welcome C=%%C Time=%c\n"
client realm = customerRealm
aaa realm = ldapRealm
}

# And this one in the "core" realm. Could write this as
# realm = ... { host = ... }, too.
host realm core = coreRouters {
address = 0.0.0.0/0
key = CoreKey
client realm = adminRealm
aaa realm = unixRealm
}

realm = unixRealm {
mavis module = groups {
resolve gids = yes
groups filter = /^(guest|staff)$/
script out = {
# copy the already filtered UNIX group access list to TACMEMBER
eval $GIDS =~ /^(.*)$/
set $TACMEMBER = $1
}
}

mavis module = external {
exec = /usr/local/sbin/pammavis pammavis -s mavis
}

user backend = mavis
login backend = mavis chpass

group = staff {
service = shell {
set priv-lvl = 15
script = {
if (cmd == "") permit # shell startup
if (cmd =~ /^configure/) permit
}
message debug = "author '%c %a'"
cmd = show { permit .* }
}
}

group = guest {
member = staff
service = shell {
cmd = show { permit .* }
message deny = "denied by t+"
}
}
}

realm = ldapRealm {
mavis module = external {
exec = /usr/local/lib/mavis/mavis_tacplus_ads.pl
setenv USE_TLS = 0
setenv LDAP_HOSTS = "192.0.2.193"
setenv LDAP_SCOPE = sub
setenv LDAP_BASE = "dc=example,dc=com"
}
user backend = mavis
login backend = mavis
pap backend = mavis
}

realm = localRealm {
user = marc {
password = clear marc
service = shell {
default command = permit
}
}
}
}

配置语法(Configuration Syntax)

以下各节所涵盖的配置节将放置在如下花括号之间。

1
2
3
id = tac_plus = {

}
  • 配置文件中的注释:

    注释可以出现在配置文件中的任何地方,从#字符开始,一直延伸到当前行的末尾。如果您需要禁用#字符的特殊含义,例如,如果您有一个密码包含一个#字符,只需将包含它的字符串括在双引号内。

  • Including Files (包含文件):

    配置文件可能引用其他配置文件,include = file

    将读取并解析file。 Shell通配符模式由glob(3)扩展。 include语句几乎可以在任何地方接受(但不能在注释或文本字符串中)。

建议的配置文件写入顺序为:

  1. global definitions
  2. hosts
  3. timespecs
  4. acls
  5. groups
  6. users

该非随机顺序背后的原因是,配置的某些部分可能会使用其他部分,并且这些部分需要在使用之前存在。

img

图:TacPlusConfig配置文件加载顺序示意图

全局配置选项(Global options):

全局配置部分可能包含以下配置指令,以及下一节详细介绍的(realm)选项。在全局级别定义的realm选项将隐含地分配给(defalut realm),并将继承给随后定义的(realm)。

Limits and timeouts:

可以专门在全局级别上指定许多全局限制(Limits)和超时(timeouts)

  • retire limit = n

    特定的守护程序实例将在处理n个请求后终止。如果需要,spawnd的实例将生成一个新实例。

    Default: unset

  • retire timeout = s

    特定的守护程序实例将在s秒后终止。如有必要,spawned将产生一个新实例。

    Default: unset

Time units(时间单位):

  • 将s,m,h或d附加到任何超时值将按预期缩放该值。

DNS:

tac_plus可以使用静态DNS条目,如果使用lwres支持进行编译,则可以使用动态DNS条目。全局级别的相关全局配置选项是:

  • dns cleanup period = s

    经过多少时间,从缓存中删除未使用的动态DNS数据。 (默认:8小时。)

  • dns preload address address = hostname

    使用地址到主机名(address-to-hostname )的映射预加载DNS缓存。

  • dns preload file = filename

    使用文件名中的地址到主机名(address-to-hostname )的映射预加载DNS缓存。

dns配置示例:

1
2
3
4
5
6
7
dns preload address 1.2.3.4 = router.example.com
dns preload file = /etc/hosts

host = router.example.com {
# "address = 1.2.3.4" is actually implied
key = mykey
}

Process-specific options(特定的进程选项):

有几个特定于进程的选项可用:

  • userid = uid

    在用户标识uid下运行守护进程。不建议使用此选项。

  • groupid = gid

    在组ID gid下运行守护进程。不建议使用此选项。

  • working directory = directory

    将当前工作目录更改为directory。

  • coredump directory = directory

    (Dump cores to directory)将核心转储到directory。你真的不需要这个。

Railroad Diagrams(铁路图):

img

图:Railroad diagram: GlobalDecl

铁路图(railroad diagram),又叫语法图(syntax diagrams),是一种表示形式语法的方式,是巴科斯范式和扩展巴科斯范式的图形化表示。

巴科斯范式(英语:Backus Normal Form,缩写为 BNF),又称为巴科斯-诺尔范式(英语:Backus-Naur Form,缩写同样为 BNF,也译为巴科斯-瑙尔范式、巴克斯-诺尔范式),是一种用于表示上下文无关文法的语言,上下文无关文法描述了一类形式语言。它是由约翰·巴科斯(John Backus)和彼得·诺尔(Peter Naur)首先引入的用来描述计算机语言语法的符号集。

尽管巴科斯范式也能表示一部分自然语言的语法,它还是更广泛地使用于程序设计语言、指令集、通信协议的语法表示中。大多数程序设计语言或者形式语义方面的教科书都采用巴科斯范式。在各种文献中还存在巴科斯范式的一些变体,如扩展巴科斯范式 EBNF 或扩充巴科斯范式 ABNF。
https://zh.wikipedia.org/wiki/%E5%B7%B4%E7%A7%91%E6%96%AF%E8%8C%83%E5%BC%8F

基本规则

  1. 从左边界开始,沿着轨道到右边界。
  2. 沿途,你在圆框中遇到的是字面量,在方块中遇到的是规则或描述。
  3. 任何沿着轨道能走通的序列都是合法的。
  4. 任何不能沿着轨道走通的序列都是非法的。
  5. 末端只有一个竖条的铁路图,表示允许在任意一对符号中插入空白。而在末端有两个竖条的铁路图则不允许。

参考资料:http://jokerliang.com/read-railroad-diagram.html

Realms:

历史上,Realms是在spawnd配置部分的listen指令中引入的:

  • Realm : n. 领域,范围;王国, 在这里可表示 ,类似domain。
1
2
3
4
5
6
spawnd = {
listen = { port = 49 }
listen = { port = 3939 }
listen = { port = 4949 realm = oneRealm}
listen = { port = 5959 realm = otherRealm}
}

Default Realm

  • 如果spawned没有提供realm名称,则tac_plus将退回到使用名为default的realm,其中包含所有在realm上下文中未定义的特定于realm的指令。

    可以在在全局配置级别选择实际的默认Realm。

    1
    2
    >   default realm = RealmName
    >

Spawnd组件的主要任务是接受连接并将其(包括相关realm)转发到tac_plus进程。然后,tac_plus使用该realm将正确的主机对象层次结构分配给连接。

使用(和定义)realm的首选语法是:

1
realm = realmName { ... }

在全局配置级别,realm可能包括主机,用户,组,MAVIS配置和各种其他配置选项。realm和主机可以参考其他realm进行认证。

更准确地说,realm的三种用途是:

  1. Authentication, Authorization and Accounting Realms

    与用户和用户组有关的所有内容(包括日志记录)都在AAA realm中进行配置。可以使用以下命令在全局,realm和主机级别选择要使用的AAA realm指令。

    1
    aaa realm = realmName
  2. Network Access Server Realms

    这是定义NAS主机对象的域。在此域(realms)上下文中定义了主机和NAS特定的参数.

  3. Network Acccess Client Realms

    可以从NAC域检索NAC特定参数,该参数可以在全局,realms和主机级别指定:nac realm = realmName

    例如,这可以用于在每个域的基础上为远程客户端启用DNS反向查找。

定义域(realms)是可选的。如前所述,在顶级(top-level)定义的域(realm)选项将分配给默认域(default realm),这实际上是aaa和nac域的默认域。

Railroad Disgrams(铁路图):

img

图:Railroad diagram: RealmDecl

Realm options(域选项):

可以在域和全局级别指定以下选项:

Logging(日志):

该软件提供以下日志:

  • Authentication

    1
    authentication log = log_destination
  • Authorization

    1
    authorization log = log_destination
  • Accounting

    1
    accounting log = log_destination

日志也可以写入多个目标(destinations):

1
2
3
4
  authentication log = log_1
authentication log = log_2
...
authentication log = log_n

有效的日志目标(destinations)是:

  • Files

    为了记录到普通磁盘文件,使用fcntl(2)文件锁定,因此建议文件驻留在本地文件系统上。尽管某些Unix实现支持NFS上的fcntl锁定,但它是出了名的不可靠,而且即使您的实现是可靠的,锁定在NFS上的效率也可能非常低。

    如果基础文件系统支持原子追加,则可能不需要fcntl(2)文件锁定。在日志destinations之前添加”>”字符将关闭文件锁定,并将日志文件处理切换为同步(synchronous)模式。

    1
    2
    3
    4
    # async
    authentication log = /var/log/tac_plus/access1.log
    # sync:
    authentication log = ">/var/log/tac_plus/access2.log"
  • Commands

    如果日志destination以”|”开头字符将运行运行目标参数其余部分的shell,并且将在标准输入上将日志消息馈送到该shell。例:

    1
    authentication log = "|exec /usr/bin/logger"

    (这里的exec并不是严格必需的,但是避免保留原本空闲的shell进程。)

  • Syslog

    可以使用syslog关键字启用登录到syslogd(8)的功能

    1
    accounting log = syslog

    (它将使用您的系统syslog(3)函数进行记录,或通过以下语法。

    1
    accounting log = Address[:UDPPort]

此外,可以使用命名的日志目标( destinations ),例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
log = mylog {
destination = 169.254.0.23 # UDP syslog
# or one of the following:
# destination = [fe80::123:4567:89ab:cdef]:514 # IPv6 UDP, with non-standard UDP port
# destination = "/tmp/x.log" # plain file
# destination = ">/tmp/x.log" # plain file
# destination = "|my_script.sh" # script
# destination = syslog # syslog(3)
#
syslog compliance = RFC3164 # this is the default for UDP syslog
# syslog compliance = RFC5424 # this loosely matches the new syslog standard
syslog facility = MAIL # sets log facility
syslog level = DEBUG # sets log level
log separator = "|" # The actual default for syslog, for others it's "\t"
}
authentication log = mylog
accounting log = mylog
authorization log = mylog

Syslog:

可以使用以下命令禁用登录syslogd(8)

1
2
> syslog default = deny
>

日志目标可能包含strftime(3)样式的字符序列,例如:

1
authorization log = /var/log/tac_plus/%Y/%m/%d.auth

自动执行基于时间的日志文件切换。默认情况下,守护程序将使用您的本地时区进行时间转换。您可以使用时区(time zone)选项(请参见下文)切换到另一种。

还有一些其他配置选项可能会有用:

  • date format = string

    这在随后定义的日志文件中定义了日期(和时间)表示形式的格式字符串。默认:

    1
    date format = "%Y-%m-%d %H:%M:%S %z"
  • log separator = string

    这将为随后定义的日志文件中的日志条目定义CSV分隔符字符串。默认:

    1
    log separator = "\t"
  • time zone = time-zone

    默认情况下,守护程序使用您的本地系统时区将内部系统时间转换为日历时间。此选项将TZ环境变量设置为时区参数。

  • umask = mode

    这将设置文件创建模式掩码。例:

    1
    umask = 0640
  • authorization log group = ( yes | no )

    进行设置,以将最后一个匹配组的名称附加到授权日志中的用户名(由单个“ /”字符分隔)。

Accounting:

所有accounting记录均以文本形式写入到用计费日志指令指定的文件(或command)中。 计费记录是包含制表符分隔字段的文本行。前6个字段始终相同。这些是:

  • timestamp
  • NAS address
  • username
  • port
  • NAC address
  • record type

在这些之后,根据计费记录类型,将写入可变数量的字段。所有形式均为attribute = value。总会有一个task_id字段。

当前属性是:

1
unknown service start_time port elapsed_time status priv_level cmd protocol cmd-arg bytes_in bytes_out paks_in paks_out address task_id callback-dialstring nocallback-verify callback-line callback-rotary

随着时间的推移,可能会添加更多内容。

如下,是示例记录(为便于阅读而换行):

1
2
3
4
5
6
7
8
1995-07-13 13:35:28 -0500  172.16.1.4  chein  tty5   198.51.100.141
stop task_id=12028 service=exec port=5 elapsed_time=875
1995-07-13 13:37:04 -0500 172.16.1.4 lol tty18 198.51.100.129
stop task_id=11613 service=exec port=18 elapsed_time=909
1995-07-13 14:09:02 -0500 172.16.1.4 billw tty18 198.51.100.152
start task_id=17150 service=exec port=18
1995-07-13 14:09:02 -0500 172.16.1.4 billw tty18 198.51.100.152
start task_id=17150 service=exec port=18

运行的时间以秒为单位,这是大多数人通常感兴趣的领域。

在NAS上,要获得与tacacs先前版本等效的计费记录,以下内容就足够了。 “Stop”记录包含连接和执行会话的运行时间。

1
2
3
4
5
6
7
8
aaa accounting system default start-stop group tacacs+
aaa accounting exec default start-stop group tacacs+
aaa accounting exec acctlist stop-only group tacacs+
aaa accounting commands 15 acctlist start-stop group tacacs+
aaa accounting network acctlist stop-only group tacacs+

line XX
accounting commands 15 acctlist

Spoofing Syslog Packets(欺骗Syslog数据包):

脚本tacspooflog.pl(与发行版捆绑在一起)可用于使syslogd认为日志直接来自路由器,而不是来自tac_plus。 例如,如果您的syslogd正在监听127.0.0.1,则可以尝试:

1
access log = "|exec sudo /path/to/tacspooflog.pl 127.0.0.1"

如果要将日志保存在一个公共位置,这可能很有用。请注意,这仅适用于IPv4。

Limits and timeouts:

在域和全局级别可以指定许多全局限制和超时:

  • connection timeout = s

    闲置至少s秒后,终止与NAS的连接。Default: 600

  • context timeout = s

    s秒钟不活动后清除上下文缓存条目。默认值:3600秒。

    Default: 3600

  • warning period = d

    将密码过期的警告期限设置为d天。Default: 14

DNS:

tac_plus可以使用静态DNS条目,如果使用lwres支持进行编译,则可以使用动态DNS条目。相关域配置选项为:

  • dns reverse-lookup = ( yes | no )

    这将设置DNS反向查询的全局默认值(默认值:no)。

  • dns timeout = Seconds

    该指令指定进行DNS反向查找时要等待的最长时间。 (默认值:0)。

Authentication:

  • password ( max-attempts = integer | backoff = seconds )

    backoff为失败的认证设置退避时间。守护进程将等待几秒钟,然后返回最终的认证失败(密码错误)消息。

    max-attempts参数限制登录时每个TACACS +会话的密码:提示的数量。当前默认为1,这意味着带有错误密码的典型登录序列如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    > telnet 10.0.0.2
    Trying 10.0.0.2...
    Connected to 10.0.0.2.
    Escape character is '^]'.

    Welcome. Authorized Use Only.

    Username: admin
    Password: ***
    Password incorrect.


    Welcome. Authorized Use Only.

    Username: admin
    Password: ****
    Password incorrect.


    Welcome. Authorized Use Only.

    Username: admin
    Password: *
    Password incorrect.

    Connection closed by foreign host.

    使用示例:

    1
    password max-attempts = 3

    (早期版本中的实际默认值为4)会将此对话框更改为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    > telnet 10.0.0.2
    Trying 10.0.0.2...
    Connected to 10.0.0.2.
    Escape character is '^]'.

    Welcome. Authorized Use Only.

    Username: admin
    Password: ***

    Password incorrect.
    Password: ****

    Password incorrect.
    Password: *****

    Password incorrect. Go away.


    Welcome. Authorized Use Only.

    Username:

    如果新的TACACS +认证失败,则由NAS决定重新启动带有新TACACS +会话的认证对话框,或关闭与用户的(Telnet / SSH / …)会话。

  • anonymous-enable = ( permit | deny )

    一些失效的TACACS+实现在启用包中发送no或无效的用户名。若设置此选项为deny,则试图在enable之前强制执行认证。此选项默认为permit。

    这可能会或可能不会。从理论上讲,启用对话框应类似于:

    1
    2
    3
    4
    5
    Router> enable
    Username: me
    Password: *******
    Enable Password: **********
    Router#

    但是,某些实现可能会在“Enable Password:”提示下重新发送用户密码。在这种情况下,您只有两种选择:无论使用enable = login 在用户组级别,将省略辅助密码查询并让用户使用其登录密码启用,或允许匿名enable(默认情况下处于disabled状态) anonymous-enable = permit (全局或主机级别),并使用在主机级别定义的enable passwords。

  • augmented-enable = ( permit | deny )

    对于在enable请求中发送$enable$而不是实际用户名的TACACS +客户端实现,这将允许使用用户名和登录密码的连接(以一个空格字符分隔)进行用户特定的认证:

    1
    2
    3
    > enable
    Password: myusername mypassword
    #

    enable [level] =需要在用户个人资料中设置登录名,此选项才能生效。

    默认: augmented-enable = deny

    augmented-enable 仅在NAS尝试验证与正则表达式匹配的用户名时才会生效^\$enab..\$$ . 例如:$enable$$enab15$)。可以使用ACL更改匹配条件:

    1
    2
    acl script = custom_enable_acl { if (user =~ ^demo$) permit deny }
    enable user acl = custom_enable_acl

Miscellaneous(杂项):

  • ingle-connection [ may-close ] = ( yes | no )

    此指令可用于允许(permit)或拒绝(deny)单连接功能。 may-close关键字告诉守护进程如果未使用关闭连接(默认值:disabled)。在主机对象级别可以覆盖此指令。

  • skip conflicting groups = ( yes | no )

    如果设置了该选项,则在组成员指令中将忽略组冲突。为给定的NAS定义的第一组获胜。

  • skip missing groups = ( yes | no )

    如果设置了该选项,则在成员指令中将忽略不存在的组。

  • client realm = realm

    在域中查找NAC参数,而不使用默认值。

User backend options(用户后端选项):

这些选项与配置MAVIS用户后端有关:

  • aaa realm = realmName

    使用域(realm)中的aaa配置(用户,组,mavis等),而不使用默认(default)配置。

  • group realm = realmName

    使用域(realm)中的aaa的组配置(用户,组,mavis等),而不使用默认(default)配置。

  • pap password [ default ] = ( login | pap )

    设置为登录时,新用户的默认PAP密码将设置为使用登录密码。

  • pap password mapping = ( login | pap )

    设置为login时,PAP认证请求将映射到ASCII登录请求。您可能希望将其用于NEXUS设备。 在主机级别可以被覆盖。

  • user backend = mavis

    从MAVIS后端获取用户数据。如果没有该指令,则只能使用本地定义的用户,并且MAVIS后端只能用于验证已知用户(password= mavis或类似)

  • pap backend = mavis [ prefetch ]

    使用MAVIS后端验证PAP密码。为了使用MAVIS后端对PAP请求进行认证,需要将其设置为mavis或prefetch。如果未设置,则将使用用户个人资料中的PAP密码。

    如果指定了prefetch,则守护进程将首先从后端检索用户的配置文件,然后根据最终在那里找到的信息对用户进行身份验证。

    该指令表示用户 user backend = mavis.

  • login backend = mavis [ prefetch ] [ chalresp [ noecho ] ] [ chpass ]

    使用MAVIS后端验证登录密码。需要将其设置为mavis或prefetch,以便使用MAVIS后端对登录请求进行身份验证。如果未设置,将使用用户个人资料中的登录密码。

    如果指定了prefetch,则守护进程将首先从后端检索用户的配置文件,然后根据最终在那里找到的信息对用户进行认证。

    该指令表示用户 user backend = mavis.

    要与启用OPIE的MAVIS模块一起使用,请添加chalresp关键字(以及(可选)添加noecho,除非您希望键入的响应显示在屏幕上)。例:

    1
    login backend = mavis chalresp noecho

    对于非本地用户,如果设置了chpass属性,并且用户在登录时提供了空密码,则可以为用户提供更改其密码的选项。这需要在MAVIS后端模块中提供适当的支持。

  • mavis module = module {}

    加载MAVIS模块 module。请参阅MAVIS文档以获取配置指南。

  • mavis path = path

    将路径添加到MAVIS模块的搜索路径。

  • mavis cache timeout = s

    将MAVIS认证数据缓存s秒。如果s设置为小于11的值,则动态用户对象仅对当前TACACS +会话有效。默认值为120秒。

  • mavis noauthcache

    禁用MAVIS模块的密码缓存。

  • mavis user filter = [ not ] acl

    仅当acl匹配时查询MAVIS用户后端。默认为

    1
    2
    acl script = __internal__username_acl__ { if (user =~ "[]<>/()|=[]+") deny permit }
    mavis user filter = __internal__username_acl__

Railroad Diagrams(铁路图):

img

图: Railroad diagram: RealmAttr

img

图:Railroad diagram: RealmAttrAuthen

Hosts(主机):

守护进程将仅与已知的NAS地址对话。来自未知地址的连接将被拒绝。

如果您想要tac_plus加密它的数据包(您几乎肯定想要这样做,因为其中可能包含用户名和密码),那么您必须指定一个(非空的)加密密钥。在与tac_plus通信的任何NAS上也必须配置相同的密钥。

要指定全局密钥,请使用类似于以下内容的语句:

1
2
3
host = 0.0.0.0/0 {
key = "your key here"
}

或者:(其中world不是关键字,而只是一些任意字符串)。

1
2
3
4
host = world {
key = "your key here"
address = 0.0.0.0/0
}

Double Quotes(双引号)

如果您的密钥包含空格,则只需要在守护进程上使用双引号即可。令人困惑的是,即使您的密钥确实包含空格,在NAS上配置匹配密钥时也绝不能使用双引号。

守护进程将拒绝来自未定义加密密钥的主机的连接。

双引号字符串中的双引号可以使用反斜杠(backslash)字符\(可以自身转义)进行转义,例如:

1
2
> key = "quo\\te me\"."
>

转换为ASCII序列,quo\te me".

主机定义中的任何CIDR范围都需要是唯一的,并且最具体的定义将匹配。对无歧义性的要求非常简单,因为某些主机对象属性(密钥、提示符、enable passwords)可能只存在一次。

在NAS上,还需要配置相同的密钥。通过发出以下命令来做到这一点:

1
2
aaa new-model
tacacs-server host 192.168.0.1 single-connection key your key here

可选的(single-connection)单连接参数指定多个会话可以使用到服务器的相同TCP / IP连接。

通常,主机声明的语法符合 :

host = [ realm realm ] name_or_ip-range { key-value pairs }`

可选realm域告诉守护程序仅将主机定义用于与相应的spawnd或client (realm)域关联的连接。例如,

1
2
3
4
5
6
7
8
9
10
11
12
id = spawnd {
listen = { port = 49 }
listen = { port = 4949 realm = space }
}

id = tac_plus {
host = earth { address = ::/0 ... }
host realm space = mars { address = ::/0 ... }
group = admin { ... }
group = alien { ... }
user = marc { member = admin@earth member = alien@mars }
}

组成员身份取决于NAS用于联系TACACS +服务器的地址和/或端口。 marc用户将是通过端口49连接的网络访问服务器的admin组的成员,对于使用端口4949的用户将是alien的成员。

在大多数情况下,可以通过IP地址或名称来引用主机。

下面说明配置文件的(Hosts)主机部分中允许的键值对。

  • key [ warn [ ( YYYY-MM-DD | s ) ] = string

    这将设置用于加密服务器和NAS之间通信的密钥。可以设置多个key,使key从一个key迁移到另一个key非常容易。如果指定了warn关键字,则在NAS实际使用该密钥时将记录一条警告消息。warn关键字可选接受一个日期参数,该参数指定警告应该在何时开始出现在日志中。

    在调试期间,使用空密钥暂时关闭加密可能会很方便:

    1
    key = ""

    完成调试后,请记住记住再次打开加密。

  • usage = ( all | any | client | server | group-membership| none )

    如果设置为client或none,那么来自与主机对象匹配的地址的TACACS+会话请求将被拒绝。同样,如果设置为server或none,则从与主机对象匹配的地址发起的登录将被拒绝。如果设置了group-membership关系,则主机定义只能用于组成员关系分配。

    此设置从超级网络(supernet)继承到其子网,并且默认为any.

    Realms:

    可以将usage与realms结合起来,以严格区分客户端和服务器主机定义:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    > # A "clients"-realm that summarizes valid client addresses for authentication:
    > realm = clients {
    > host = ::0/0 { usage = none }
    > host = 172.17.2.0/24 { usage = clients }
    > }
    >
    > # Use the "clients" realm for looking up NACs:
    > client realm = clients # This is the global definition, but ...
    >
    > # ... the "client realm" setting can be used on a per-host basis, too:
    > host = router { ... client realm = clients ... }
    >
  • inherit = ( yes | no )

    如果设置为no,则当前主机声明不会从其超级网络(supernet)继承配置摘要(例如:key, enable passwords)。默认为yes。

  • name = string

    将名称字符串分配给主机对象。这与地址关键字,可以用来形成主机组。如果您已经在初始的host = 语句中分配了名称,则不要使用此属性,并且要注意在用户和组之前定义主机,否则组成员资格分配可能会失败,可能会以静默方式失败。

  • address = cidr

    将cidr指定的地址范围添加到当前主机定义中。

    img

    ​ Railroad diagram: CIDR

  • address file = file

    将文件中的地址添加到当前主机定义。 Shell通配符模式由glob(3)扩展。

  • client realm = realm

    在域中查找NAC参数,而不使用默认值。

  • dns reverse-lookup = ( yes | no )

    此指令为相应的主机启用或禁用DNS反向查找。

  • dns timeout = Seconds

    该指令指定进行DNS反向查找时要等待的最长时间。 (默认值:0)。

  • single-connection ( may-close ) = ( yes | no )

    该指令可用于允许或拒绝特定主机对象的单连接功能。 may-close关键字告诉守护程序如果未使用则关闭连接。

    Caveat Emptor(需留心):

    单连接不按预期工作的可能性很小。路由器中的单连接实现,甚至在这个守护进程中实现的连接(或者可能两者都有)可能有问题。如果你注意到奇怪的AAA行为无法解释,那么尝试禁用路由器上的单连接。

  • template = ( address | name )

    这使用地址或name的现有主机定义的一部分作为当前主机声明的模板。仅复制banners,key,enablepasswords andcontent,并且不进行递归查找。

Timeouts:

可以指定连接超时:connection timeout = s

闲置至少s秒后,终止与该NAS的连接。默认为全局选项。

Authentication:

在主机对象级别可以使用以下与认证相关的指令:

  • aaa realm = realmName

  • access acl = ( [ permit ] | deny ) [ not ] acl

    与该指令不匹配的认证请求将被拒绝。

  • password ( max-attempts = integer | backoff = seconds )

  • pap password mapping = ( login | pap )

    设置为login时,PAP认证请求将映射到ASCII登录请求。您可能希望将其用于NEXUS设备。

  • default user = name

    该指令为来自与该主机对象匹配的主机的连接设置默认用户名。例如:

    1
    host = nms { address = 1.2.3.4 user = nmsuser }

    将告诉守护程序不要查询来自1.2.3.4的连接的用户名,而是使用nmsuser。

    小心使用此选项。在转换到TACACS+环境时,它可能很方便,但有几个严重的问题,第一个问题是路由器不知道用户名,这意味着通过TACACS+的授权无法工作。

  • default group = name

    对于没有任何组成员身份的用户,此指令可用于分配一个。它用于源自此主机对象的连接。例如,您可以使用以下方法拒绝没有组成员身份的用户访问:

    1
    2
    3
    host = ... { default group = no_login }
    acl script = no_login { deny }
    group = no_login { acl = no_login }
  • enable [ level ] = ( permit | deny | login | ( clear | crypt) password )

    该指令可用于设置主机特定的enable passwords,使用登录密码或允许(无密码)或拒绝任何启用尝试。级别默认为15。

    在主机级别指定的enable passwords的优先级比在用户或组级别定义的启用密码的优先级低。

    Password Hashes(密码哈希):

    您可以使用openssl passwd实用工具来计算密码哈希。例如,

    1
    2
    > openssl passwd -1 clear_text_password
    >

    返回MD5哈希,而:

    1
    2
    > openssl passwd -crypt clear_text_password
    >

    返回DES哈希值。

    DES密码被设计为截断为八个字符。

    您可以通过在NAS上进行配置来通过TACACS + enable:

    1
    aaa authentication enable default group tacacs+ enable
  • anonymous-enable = ( permit | deny )

    一些失效的TACACS+实现在启用包中发送no或无效的用户名。设置此选项可在启用前强制执行用户认证。此处设置此选项优先于全局选项。

  • augmented-enable = ( permit | deny )

    对于在enable请求中发送$enable$而不是真正的用户名的TACACS+客户端实现,这将允许使用用户名和登录密码的连接(用单个空格字符分隔)进行特定于用户的认证。此处设置此选项优先于全局选项。

    enable [level] =需要在用户个人资料中设置登录名,此选项才能生效。

Banners and Messages:

守护程序允许将各种(banners)显示给用户:

  • welcome banner = string

  • motd banner = string

  • failed authentication banner = string

    失败的认证标语将在认证尝试最终失败时显示。

  • reject banner = string

    如果连接被主机,用户或组级别上定义的访问ACL拒绝,则显示拒绝banners代替欢迎消息。

  • message = string

这些文本显示的时间很大程度上取决于实际的登录方法:

Context Directive Login via Telnet Login via SSHv1 Login via SSHv2
host welcome banner displayed beforeUsername: not displayed displayed beforePassword:
host reject banner displayed before closing connection not displayed not displayed
host motd banner displayed after successful login not displayed displayed after successful login
host failed authentication banner displayed after unsuccessful login not displayed displayed after unsuccessful login
user or group message displayed aftermotd banner not displayed displayed aftermotd banner

果为用户设置hushlogin,则不会显示motd banner或在用户个人资料中定义的消息

所有横幅和消息均支持strftime(3)样式的转换规范,以及以下转换序列:

%%r router address
%%R router DNS name (fallback: IP address)
%%c client address
%%C client DNS name (fallback: IP address)
%%p router port
%%u username
%%% literal %

示例:

1
2
3
4
5
host = ... {
...
welcome banner = "Welcome. Today is %A.\n"
...
}

Inheritacnce and Hosts:

对于主机查找,守护进程首先查找最特定的主机定义。如果该定义(或请求的值)不存在,它将查找下一个不那么特定的定义。这个过程在整个(IPv6) CIDR层次结构中继续进行,直到找到匹配项为止。

换句话说:对于主机参数,与此定义的参数最匹配的主机定义匹配。

例如,如果主机192.168.1.15连接到服务器,则服务器需要知道要使用哪个加密密钥。

在IPv6映射的CIDR表示法(守护程序在内部使用)中,IPv4 CIDR范围

192.168.1.15/32等于:0000:0000:0000:0000:0000:FFFF:C0A8:010F/128

守护程序将在主机定义中搜索192.168.1.15和(定义的)超网的密钥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0000:0000:0000:0000:0000:FFFF:C0A8:010F/128
0000:0000:0000:0000:0000:FFFF:C0A8:010F/127
0000:0000:0000:0000:0000:FFFF:C0A8:010E/126
0000:0000:0000:0000:0000:FFFF:C0A8:010C/125
...
0000:0000:0000:0000:0000:FFFF:C000:0000/98
0000:0000:0000:0000:0000:FFFF:8000:0000/97
0000:0000:0000:0000:0000:FFFF:0000:0000/96
0000:0000:0000:0000:0000:FFFE:0000:0000/95
0000:0000:0000:0000:0000:FFFC:0000:0000/94
...
0000:0000:0000:0000:0000:0000:0000:0000/3
0000:0000:0000:0000:0000:0000:0000:0000/2
0000:0000:0000:0000:0000:0000:0000:0000/1
0000:0000:0000:0000:0000:0000:0000:0000/0

找到的第一个密钥将被使用,因为它是最具体的一个。

默认情况下,将继承welcome banner,motd banner,key,enable,anonymous-enableandcontent。可以为主机对象关闭继承: inherit = no

Railroad Diagrams:

img


Railroad diagram: HostDecl

img

Railroad diagram: HostAttr

img

Railroad diagram: EnableExpr

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
host = 10.0.0.0/8 {
name = customer1
key = "your key here"
welcome banner = "\nHitherto shalt thou come, but no further. (Job 38.11)\n\n"
enable 15 = clear whatever
}

host = test123 {
address = 10.1.2.0/28
address = 10.12.1.30/28
address = 10.1.1.2
# key/banners/enable will be inherited from 10.0.0.0/8 by default,
# unless you specify "inherit = no"
address file = /some/path/test123.cidr
prompt = "\nGo away.\n\n"
}

Time Ranges(时间范围):

timespec对象可用于基于时间的配置文件分配。支持cron和Taylor-UUCP语法;有关详细信息,请参见本地crontab(5)和/或UUCP手册页。句法:

1
timespec =` *timespec_name* `{ "`*entry*`"` [ ... ] `}

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Working hours are from Mo-Fr from 9 to 16:59, and
# on Saturdays from 9 to 12:59:
timespec = workinghours {
"* 9-16 * * 1-5" # or: "* 9-16 * * Mon-Fri"
"* 9-12 * * 6" # or: "* 9-12 * * Sat"
}

timespec = sunday { "* * * * 0" }

timespec = example {
Wk2305-0855,Sa,Su2305-1655
Wk0905-2255,Su1705-2255
Any
}

Railroad Diagrams:

img

Railroad diagram: TimespecDecl

Access Control Lists(访问控制列表):

访问控制列表(acl)由一系列访问控制表达式(Access Control Expressions ACEs)组成。只要其中一个ACEs匹配,ACL就会匹配。构成ACL的ACEs是按顺序处理的。如果每个定义的子类型表达式至少有一个类型匹配,则ACE匹配。以身份命名的ACs成为具有相同名称的ACL的一部分。

标准ACL语法为:

1
acl` `=` *name* `{` ( (`nac` ( `=` [ `not` ] (*HostName*|*cidr*) ) | ( [ `dns` ] `regex =` [ `not` ] *NacRegex* )) | (`nas` ( `=` [ `not` ] (*HostName*|*cidr*) ) | (`regex =` [ `not` ] *NasRegex* )) | (`port regex =` [ `not` ] *PortRegex* ) | (`acl =` [ `not` ] *ACLName* )* `}` (`time =` [ `not` ] *TimeSpecName* )* `}

或者,可以使用脚本:

1
acl script = name{ ... }

下一章将详细介绍后者。

对于标准的ACL语法,请查看下面的“铁路图”,希望会变得更加清楚。

ACE将按照您定义它们的顺序进行评估。例如:

1
2
3
4
5
6
7
8
9
acl = myacl {
nac = 10.0.0.0/8
nac = 11.0.0.0/8
nas = somehostobjectname
}

acl = myacl {
time = workinghours
}

由两个ACEs组成,这些ACE组成一个名为“ myacl”的ACL。此ACL匹配

  • 适用于10.0.0.0/8或11.0.0.0/8中的客户端以及服务器某些hostobjectname的一部分
  • 仅在工作时间内,无论涉及什么客户端或服务器(或端口)

当使用dns关键字时,根据NACs dns反向映射执行NAC正则表达式匹配。这只有在a)软件是在lwres支持下编译的,b) lwresd实际运行的情况下才能工作。但是,请记住,DNS不一定是可信的,查找可能会失败。请记住,最好在您的NAS上启用单连接。这允许守护进程利用缓存反向映射结果的优势。

Railroad Diagrams:

img

Railroad diagram: ACLDecl

img

Railroad diagram: ACLExpr

Rewriting User Names(改写用户名):

这是实验性的。它需要使用PCRE v2支持构建二进制文件(使用–with-pcre2配置选项)。

主机可以引用在域级别定义的重写配置文件来替代用户名。以下示例代码将admin和root都映射到marc,并将所有其他用户名都转换为小写:

1
2
3
4
5
6
7
8
9
10
11
rewrite = rewriteRule {
rewrite /^admin$/ marc
rewrite /^root$/ marc
rewrite /^.*$/ \L$0
}

host = ... {
...
rewrite user = rewriteRule
...
}

请记住,这是实验性的…

Scripts:

脚本当前可用于ACL并用于服务声明范围:

  • acl script = acl_name { tac_action … }

    Example:

    1
    2
    3
    acl script = myacl123 {
    if (nas == 1.2.3.4 || nac = SomeHostName || nac-dns =~ /\\.example\\.com$/) deny
    }
  • script = { tac_action … }

    Example:

    1
    2
    3
    4
    5
    6
    7
    user = joe {
    service = shell {
    script = {
    if (cmd == "") permit # required for shell startup
    if (cmd =~ /^(no\s)?shutdown\s/) permit }
    }
    }

Syntax:

(Script)脚本包含一系列动作:

img

Railroad diagram: TacAction

最终返回的动作是:permit和deny。在脚本结束时,会暗示返回,此时守护进程将继续处理shell上下文中配置的cmd语句或标准ACL (ACL上下文中)。赋值操作(context =, message =)只在shell上下文中有意义。

设置上下文变量仅在shell上下文中才有意义。请参阅相应部分中的示例

条件语法为:

img

Railroad diagram: TacCond

Users and Groups(用户和组):

用户和组声明非常相似。主要区别在于组是静态的,而用户声明可以在运行时通过MAVIS后端添加。

用户可以是组的成员(也称为role或profile)。实际的组成员身份可能取决于各种因素,例如用户所在的NAS,NAC或时间范围。每个组又可以是另一个组的成员,依此类推。

用户和组声明的基本形式是:

1
user = username { ...  }

或分别:

1
group = groupname {  ...  }

用户或组声明可以包含键值对和服务声明。

User-only options:

以下声明仅在用户上下文中有效:

  • login = ( ( clear | crypt ) password| mavis | permit | deny )

    登录password认证Shell登录到服务器。

    1
    2
    login = crypt aFtFBT4e5muQE
    login = clear Ci5c0

    对于crypt, 可以使用DES或MD5哈希码。

    如果改用mavis关键字,则将通过MAVIS后端查找密码,它不会被缓存。

    尽管配置文件中有静态用户声明,但如果您想在外部系统进行认证,此功能可能很有用。

  • pap = ( ( clear | crypt ) password | mavis | permit | deny )

    pap认证PAP登录到服务器。就像login时一样,密码不需要使用明文形式,而是可以使用DES(或MD5)进行散列,也可以通过MAVIS后端进行查找。

  • arap = ( clearpassword | permit | deny )

    对于ARAP认证,需要输入明文密码。

  • chap = ( clearpassword | permit | deny )

    对于CHAP认证,需要使用明文密码。

  • ms-chap = ( clearpassword | permit | deny )

    对于 MS-CHAP认证,需要使用明文密码。.

  • opap = ( clearpassword | permit | deny )

    对于outgoing PAP n认证, 需要使用明文密码。

  • password = ( clearpassword | permit | deny )

    该指令将所有先前未定义的密码(OPAP除外)设置为给定的明文密码。保留该指令仅是为了向后兼容,不建议使用。

  • password [ acl [ not ] acl ] {}

    该指令允许指定与ACL相关的密码。例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    acl jumpstation = { nac == 10.255.0.85 }

    user = marc {
    password acl jumpstation {
    login = permit
    pap = permit
    }
    password {
    login = clear myLoginPassword
    pap = clear myPapPassword
    }
    }

Group-only options:

以下声明仅在组上下文中有效:

  • template = groupname

    该指令将组定义从groupname合并到当前组。已经存在的定义优先。

USer and Group options:

以下键值对在用户和组上下文中均有效:

Limits:

用户或组的有效性可能受到各种属性的限制:

  • acl = ( [ permit ] | deny ) [ not ] acl

    用户或组配置文件的有效性可能会受到ACL的限制。可以指定多个ACL并按顺序进行评估。

  • valid from = ( YYYY-MM-DD | s )

    该配置文件将从给定的日期开始有效,该日期可以以ISO8601日期格式指定,也可以以UTC自1970年1月1日起的秒数指定。

  • valid until = ( YYYY-MM-DD | s )

    给定日期之后,该个人资料将无效。

  • client [ regex ] = ( deny | [ permit ] ) string [ , … ]

    作为ACL的替代(或补充)(请参见上文),某些基于NAC的有效性限制可以直接放置在用户(或组)对象中。例如,要将登录限制为某个IP范围或主机组:

    1
    2
    client = 10.99.0.0/16
    client = deny customer3

    如果使用regex关键字,则string应该是有效的正则表达式。正则表达式搜索代价较大,仅在NAS发送的NAC地址不是IP地址时使用。正则表达式客户端匹配的示例:

    1
    2
    3
    4
    5
    6
    7
    # if compiled with PCRE:
    client = deny /^async$/
    client regex = /^console$/

    # without PCRE:
    client = deny "^async$"
    client regex = "^console$"

判断顺序:

请注意在client声明之前会检查ACL。

对于client定义,将在正则表达式之前检查IP地址,然后按定义它们的顺序判断后者。

  • server = ( deny | [ permit ] ) string [ , … ]

    这将用户帐户的有效性限制为某些NAS地址或组,例如:

    1
    2
    server = 1.2.3.4/32
    server = nas01
Messages:

这些选项处理向用户显示消息。

  • message = string

    登录时显示给用户的消息。

  • hushlogin = ( yes | no )

    将hushlogin设置为yes可防止守护程序在登录时显示motd和user消息。

    Hush : 安静, 寂静

Enable passwords:

启用密码可以按优先级,主机,用户或组级别指定:

  • enable [ level ] = ( permit | deny | login | ( clear | crypt ) password )

    此指令可用于设置用户或组特定的启用密码,使用登录密码,或允许(没有密码)或拒绝任何启用尝试。启用加密在组或用户级别定义的密码优先于在主机级别定义的密码。level默认值为15。

    NAS上普通用户的默认命令级别通常为1。当用户enables时,可以使用NAS enable命令将这个级别重置为0到15之间的值。如果她没有指定级别,那么enable的默认级别是15。

MAVIS options:

以下MAVIS相关选项适用于组和本地定义的用户:

  • mavis realm = realmName

    对于password = mavis的本地定义用户(或密码为mavis的用户),此指令选择用于MAVIS认证的域。

Group membership:

组成员资格是使用member指令指定的:

  • member [ acl [ not ] acl ] = string [ , … ]

    该指令定义组成员身份,视情况取决于NAS服务器的地址或某些访问列表。例如,可以配置:

    1
    2
    3
    4
    5
    6
    7
    host = campus { ... }
    host = remote { ... }
    host = router { ... }
    timespec = workinghours { ... }
    group = admins { ... }
    group = staff { ... }
    group = guest { ... }

    加上一些ACL:

    1
    2
    3
    acl oncampus = { nac = campus }
    acl viavpn = { nac = remote }
    acl atwork = { nac = campus time = workinghours }

    然后基于后者成为组成员:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    user = adminuser { member = admins }
    user = employee {
    ...
    member acl atwork = staff@router
    member acl viavpn = staff
    member acl remote = guest
    ...
    }
    user = guest {
    ...
    member acl atwork = guest
    ...
    }
    user = myself {
    ...
    member = admins@router
    member = staff
    ...
    }

    member 指令要按ACL名称排序,最后没有ACL的定义。这是在解析时强制执行的。

    可以指定备用组,组名之间用 /分隔:

    1
    member = dialin/callback@10.11.12.13

    在这里,组成员将默认为拨号组。但是,附加分隔字符(使用 separation tag = character 指令可更改),然后在登录时回调到用户名,将选择相应的回调组配置文件。

    再重复一次:任何用户都可以是一个主组的成员。这个例子中的拨号/回调语法实际上意味着:用户可以自由选择在登录时,他是否想成为拨号XOR回调的成员。用户fred可以认证为fred(或freddialin)来获得dialin成员资格,fredcallback将把他分配到回调组。

    可以使用tag指令(请参见下文)覆盖用户的选择。

    组成员身份可能取决于NAS IP,例如fred可能会喜欢:

    1
    2
    member = test1@nas1
    member = test2@nas2

    在他的profile中。 就像用户一样,组可以是(其他)组的成员:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    group = test1 { ... }
    group = test2 { ... }

    group = test2 {
    ...
    member = test1
    member = test2@nas1
    ...
    }

    不支持同时(非分层)组中的成员身份。

    由于在解析配置文件时解析了组成员身份,因此在用作成员定义中的参数之前,必须先定义组和主机。

  • nas default restriction = ( cidr | host )

    除非另有说明,否则将组的使用限制为指定的主机。例:

    1
    2
    3
    4
    group = group1 { nas default restriction = host1 }
    group = group2 { }
    group = group3 { nas default restriction = host1 }
    user = user1 { member = group1,group2,group3@host3 }

    等同于

    1
    2
    3
    4
    group = group1 { }
    group = group2 { }
    group = group3 { }
    user = user1 { member = group1@host1,group2,group3@host3 }

    注意:对于备用组规范(例如member = group1 / group2),将忽略nas默认限制

  • tag ( acl [ not ] acl ) = string

    如上所述,用户可以在登录时使用user*group语法手动选择(允许的)组配置文件。您可以使用用户或组配置文件中的tag指令覆盖用户的选择。此外,您还可以进行基于acl的标记选择。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    timespec = workinghours { "* 9-16 * * 1-5" "* 9-12 * * 6" }
    timespec = weekend { "* * * * 6-1" }
    timespec = changewindow { "* 22-23 * * Sat" "* 0-3 * * Sun" }

    acl helpdesk = {
    time = workinghours
    nac = internal_lan
    nas = somecustomer
    }

    acl remoteadmin = {
    time = changewindow
    nac = dialin
    }

    user = fred {
    login = clear test
    member = admin/ro/emergency
    tag acl helpdesk = admin
    tag acl remoteadmin = emergency
    tag = ro
    }

    在工作时间,fred将是admin组的成员,但前提是他的客户端IP地址是内部LAN的一部分,并且他在某个NAS上。在更改窗口时间,他将是emergency小组的成员,但需要来自拨入池。在这些时间之外,他是ro时间的一员。

    Tag定义是按顺序计算的。如果没有匹配的定义,则使用用户的会话tag(使用user*group语法登录时选择的组)。如果没有给出组标记,则选择成员定义中的第一个组。

    在大多数情况下,使用成员acl语法而不是tag acl可能是更好的主意。

Railroad Diagrams:

img

Railroad diagram: UserDecl

img

Railroad diagram : GroupDecl

img

Railroad diagram: PasswordExpr

img

Railroad diagram: PasswordExprHash

img

Railroad diagram: UserAttr

img

Railroad diagram: UserMessage

img

Railroad diagram: GruopAttr

img

Railroad diagram: GroupOnlyAttr

Service Restrictions(服务限制):

  • default service = ( permit | deny )

    这定义了应允许还是拒绝在用户配置文件中未明确定义的服务。

  • prohibit service = service …

    使用它来覆盖默认服务规范。例如,明确拒绝X.25服务:

    1
    prohibit service = x25

Service Definitions(服务定义):

服务定义可能会出现在用户和组部分中。可以很容易地使服务依赖于ACL:

1
service` ( `acl` [ `not` ] ACLName `=` *service* `{` *...* `}

在任意服务定义中可能会出现几个通用配置属性。特别是:

  • default attribute = ( permit | deny )

    该指令指定守护程序是接受还是拒绝NAS发送的未知属性(默认值:deny)。

  • acl = ( [ permit ] | deny ) [ not ] acl

    就像用户和组配置文件一样,可以使用ACL限制服务。

  • ( set | optional ) attribute = value

    定义强制和可选属性-值对。例:

    1
    set priv-lvl = 15

    有关强制和可选AV-pairs的详细说明,请参见下面的“The Authorization Algorithm””部分

  • return

    照原样使用当前服务定义。这使守护程序停止检查当前用户(或组)所属的组中的同一服务。

其他配置属性是特定于服务的,并且仅在某些情况下有效:

SHELL (EXEC) Service

Shell启动应提供适当的服务定义。

1
service = shell { }

大括号内的有效配置指令为:

  • default cmd = ( permit | deny )

    该指令指定守护程序是接受还是拒绝未明确允许的命令(默认值:deny)。

  • message ( permit | deny ) = string

    这指定在接受或拒绝命令时要呈现给用户的消息。字符串中可识别的字符串替换是:命令(command )名称为%c,命令参数( arguments)为%a,当前设置的上下文( context)为%C。例:

    1
    2
    message permit "Permitted '%c %a'"
    message deny "Denied '%c %a'"

    此指令也可能出现在cmd部分中,在该地方它会覆盖service部分的定义。

  • 1
    cmd =command{ ... }

    cmd部分允许或拒绝命令和命令参数。例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    cmd = show {
    deny /^(running|startup)-config/
    deny tech-support
    permit //
    message deny = "Try this again and your account will be revoked."
    message permit = "This data is to be considered confidentional."
    }
    cmd = reload {
    permit //
    message permit = "You hopefully know what you're doing ..."
    }

    正则表达式语法为POSIX,如果在编译时启用,则为PCRE。

如果不确定给路由器实际发送了哪些命令和参数,则可以简单地修改用户(或组)配置文件以显示登录会话中的命令和参数。例如:

1
2
3
4
5
6
7
8
9
10
user = ... {
...
debug = CMD
...
service = shell {
...
message debug = "author: 'cmd = %c { permit /^%a$/ }"
...
}
}

将显示配置摘要以允许使用PCRE语法的命令,例如:

1
2
3
4
5
Router#conf t
author: 'cmd = configure { permit /^terminal <cr>$/ }'

Enter configuration commands, one per line. End with CNTL/Z.
Router(config)#
Non-Shell Service:

例如。对于PPP,可以使用协议定义:

1
2
3
service = ppp {
protocol = ip { set addr = 1.2.3.4 }
}

使用default protocol = permit 或者 default protocol = deny ,为服务声明中未明确定义的协议指定默认值。 (默认:deny)。

对于Juniper网络特定的授权服务,请使用:

1
2
3
4
service = junos-exec {
set local-user-name = NOC
# see the Junos documentation for more attributes
}

同样,对于Raritan Dominion SX IP控制台服务器:

1
2
3
4
service = dominionsx {
set port-list = "1 3 4 15"
set user-type = administator # or operator, or observer
}

Quotes:

如果您的路由器需要双引号(double-quoted)(例如Cisco Nexus设备),则可以建议解析器自动添加这些值:

1
2
3
4
> service = shell {
> set shell:roles="\"network-admin\""
> }
>

和:

1
2
3
4
5
> service = shell {
> double-quote-values = yes
> set shell:roles="network-admin"
> }
>

是等效的,但后者更具可读性。

Host-group specific services(主机组特定服务):

通过将@host附加到service name,可以配置特定于NAS的服务。在此,host是主机对象的名称,而不是IP地址或CIDR范围。例如,用户的PPP地址在一个特定的NAS上可能是静态的,但在其他所有位置上都是动态的:

1
2
3
4
5
host = dialin { address = ... }
user = ... {
service = ppp { protocol = ip { } }
service = ppp@dialin { protocol = ip { set addr = 1.2.3.4 } }
}

尽管可以使用主机特定的组成员身份来实现相同目的,但这为动态身份验证后端增加了一些灵活性。

CLI Contexts:

当与单连接(single-connection)一起使用并被告知时,守护程序将尝试记住命令上下文。这允许仅对一个接口使用shutdown系列命令,但对其他所有接口均拒绝使用它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
user = john {
password = clear doe
service = shell {
default cmd = permit
set priv-lvl = 15
script = {
if (cmd == "") permit # shell startup

if (cmd =~ /^interface FastEthernet 0\/1 /) {
message = "Context has been set. \"[no] shut\" should work for you."
context = FE
permit
} else if (cmd =~ /^interface/){
message = "Context has been reset."
context = ""
permit
}
if (context == FE) {
if (cmd =~ /^shutdown/) permit
if (cmd =~ /^no shutdown/) permit
deny
}
}
cmd = shutdown { deny . }
cmd = no { deny /^shutdown/ }
}
}

用户和组配置示例:

在这里,我们声明两个用户fred和lily,以及两个组admin和staff。 fred是组管理员的成员,而组admin又是组staff的成员。 lily不是任何组的成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
group = admin {
# group admin is a member of group staff
member = staff
service = shell {
set priv-lvl = 15
}
}

group = staff {
# group staff is not a member of any group
}

user = lily {
# user lily is not a member of any group
# and has nothing else configured as yet
}

user = fred {
# fred is a member of group admin on 0.0.0.0/0
member = admin
# fred is a member of group staff when logging in on 10.0.0.0/8
member = staff@10.0.0.0/8
# fred is a member of group admin when logging in on hosts
# defined in hostgroup test123
member = admin@test123
# fred may only log in from a client in 172.16.0.0/24 ...
client = 172.16.0.0/24
# ... or from whatever address is defined in some host object test123
client = test123
}

Railroad Diagrams:

img

Railroad diagram: ServiceDecl

img

Railroad diagram: ServiceAttr

img

Railroad diagram: Acl

img

Railroad diagram: AttrDefault

img

Railroad diagram: AVPair

img

Railroad diagram: ShellDecl

img

Railroad diagram: ShellAttr

img

Railroad diagram: TacScript

img

Railroad diagram: ShellCommandDecl

img

Railroad diagram: CmdDefault

img

Railroad diagram: ProtoDeafult

img

Railroad diagram: ProtoDecl

通过MAVIS配置非本地用户:

MAVIS配置是可选的。如果您对主配置文件中的用户配置感到满意,则不需要它。

MAVIS后端可以基于例如LDAP信息动态地创建用户条目。

对于 PAP 和 LOGIN:

1
2
pap backend = mavis
login backend = mavis

在全局部分中,将认证授权给MAVIS子系统。静态定义的用户仍然有效,并且具有更高的优先级。

默认情况下,MAVIS用户数据将被缓存120秒。您可以使用cache timeout = seconds 在全局配置部分。

配置本地用户进行MAVIS身份验证

在某些情况下,您可能希望将用户定义保留在纯文本配置文件中,但是仍然要针对某些外部系统进行身份验证,例如LDAP或RADIUS。为此,只需指定以下一项在相应的用户定义中。

1
2
3
login = mavis
pap = mavis
password = mavis

递归和组:

通常,当守护进程查找值时,它将首先查看用户是否对该值具有自己的定义。如果不是,则查看她是否属于某个组,如果属于,则查看该组是否已定义值。如果没有,则此过程将在组的层次结构(一个组可以是另一个组的成员)中继续进行,直到找到一个值,或者不再有gmaryroups。

此递归过程是针对到期日期的查找以及授权参数(请参阅下文),而不是用户密码。

因此,一种典型的配置技术是将用户放入组中,并在组声明中指定尽可能多的组范围特征。然后,可以根据需要使用单个用户声明覆盖所选用户的组设置。

配置用户认证:

用户认证可以分别为PAP,ARAP,CHAP和常规登录。全局用户认证必须使用明文(clear text)认证。

以下为用户Mary分别为ARAP,inbound和outboud CHAP, inbound PAP,outbound PAP和普通登录分配了五个不同的密码:

1
2
3
4
5
6
7
user = mary {
arap = clear "arap password"
chap = clear "chap password"
pap = clear "inbound pap password"
opap = clear "outbound pap password"
login = crypt XQj4892fjk
}

如果user backend = mavis 如果在“全局”部分中配置,则MAVIS后端将查找在配置文件中找不到的用户。您应该考虑将此选项与更复杂的后端(特别是LDAP和ActiveDirectory)结合使用,或者在您不愿意将现有数据库用户数据复制到配置文件时使用。对于通过MAVIS后端查询的用户,

pap backend = mavis 或者 login backend = mavis (同样,在配置文件的全局部分)将导致MAVIS后端执行PAP和/或登录认证(例如,通过执行LDAP绑定),而忽略用户个人资料中的任何相应密码定义。

如果只希望使用MAVIS后端对配置文件中定义的用户进行身份验证,只需将相应的PAP或登录密码字段设置为mavis(在这种情况下,无需添加user backend = mavis指令):

1
user = mary { login = mavis }

配置到期时间:

从有效截止日期开始,将导致配置文件无效。有效日期格式为ISO8601,也是自1970-01-01开始的绝对秒数。

1
2
3
4
user = lol {
valid until = YYYY-MM-DD
login = clear "bite me"
}

用户登录时会向用户发送过期警告消息,默认情况下从过期日期前14天开始,但是可以通过警告期限指令进行配置。

补充个人资料有效期,在给定日期激活配置文件。

1
valid from = YYYY-MM-DD

在NAS上配置认证:

在NAS上,配置登录认证,请尝试

1
2
aaa new-model
aaa authentication login default group tacacs+ local

不要把自己关在外面。(Don’t lock yourself out.

发出此命令后,如果没有正确配置了用户名和密码的有效TACACS +守护程序,您将无法再创建新的NAS登录信息。

作为设置时的安全措施,您应该配置一个启用密钥,并将其作为最后的认知方法,因此,如果您的TACACS +守护程序无法响应,您将可以使用NAS启用密码进行登录。为此,请配置:

1
2
> aaa authentication login default group tacacs+ enable
>

或者,如果您有本地帐户:

1
2
> aaa authentication login default group tacacs+ local
>

如果所有其他方法都失败了,并且由于配置问题您发现自己已被锁定在NAS之外,那么Cisco CCO网页上有关从丢失的密码中恢复的部分将帮助您寻找出路。

配置授权(Authorization):

必须在NAS和守护进程上都配置授权才能正常运行。默认情况下,NAS将允许所有操作,直到您将其配置为向守护程序发出授权请求为止。

在守护程序上,情况恰好相反:默认情况下,守护程序将拒绝未明确允许的任何内容的授权。授权允许守护程序完全拒绝命令和服务,或者基于每个用户修改命令和服务。守护程序上的授权分为两个独立的部分:命令和服务。

授权命令:

Exec命令是在Cisco exec提示符下键入的那些命令。当NAS请求授权时,整个命令将发送到tac_plus守护程序进行授权。

通过指定PCRE(Perl Compatible Regular Expressions)或egrep-style参数的正则表达式来匹配命令授权,以匹配命令参数以及拒绝或允许的操作。

不区分大小写的模式匹配:

默认情况下,正则表达式匹配不区分大小写。可以通过指定更改:

1
2
> regex-match-case = yes
>

如果POSIX参数包含空格或特殊字符,则必须将参数括在双引号(”)中。对于双引号内的文本,将应用C解析规则。特别地,反斜杠\必须转义为\\。 PCRE模式需要用斜杠(/ pattern /)括起来,POSIX和PCRE语法都可以在同一配置文件中使用。

以下配置示例允许用户Fred运行以下命令:

1
2
3
telnet 131.108.13.any_number
telnet 128.any_number.12.3
show running-config interface anything

所有其他命令均被拒绝(默认情况下)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
user=fred {
# default service = deny
service = shell {
# default cmd = deny
cmd = telnet {
# permit specified telnets
# POSIX:
permit ^131\.108\.13\.[0-9]+$
# PCRE:
permit /^128\.\d+\.12\.3$/
}
cmd = show {
# permit show commands
# PCRE:
permit /^running-config interface/
}
}
}

空格,whitespace:

如果指定的任何非PCRE参数列表包含空格或制表符,则必须将其用双引号引起来。无论如何,PCRE表达式都应包含在斜杠中。

用户键入的命令和参数将与您在配置文件中指定的正则表达式匹配(按出现顺序)。第一次成功匹配将执行关联的操作(允许或拒绝)。如果没有匹配项,则默认情况下将拒绝该命令。

相反,以下配置示例可用于拒绝命令:

1
telnet 131.108.13.any_number

并允许所有其他参数,因为最后一行将匹配任何参数列表。由于“default service = permit”子句,因此允许所有其他命令和服务。

注意:默认语句必须是user子句中的第一条:

1
2
3
4
5
6
7
8
9
10
user=fred {
default service = permit
service = shell {
cmd = telnet {
# allow all telnet commands except to 131.108.13.*
deny ^131\.108\.13\.[0-9]+
permit .*
}
}
}

仅当指定匹配项时,才会锚定匹配项,因此请拒绝131.108.13.[0-9] +命令中任何位置的匹配项。要锚定匹配项,请在正则表达式的开头使用^。

当命令具有多个参数时,用户可以以许多不同的排列输入它们。创建在这些条件下可靠地授权命令的正则表达式可能很麻烦,因此管理员可能希望考虑其他执行授权的方法,例如通过在NAS本身上配置NAS本地特权启用级别。

命令扩展:

对于命令授权,Cisco NAS会将所有命令扩展为全名,例如,当您在NAS上键入config t时,它将被扩展到配置终端,然后再发送到守护程序,因此您无需列出所有可能的收缩命令。

在用户级别,即在用户声明的大括号内,没有明确授权的服务或命令的用户的默认设置是拒绝该服务或命令。以下指令将默认允许服务或命令:

1
2
3
user = lol {
default service = permit
}

注意:此指令必须首先出现在用户声明中

在服务授权级别,即在服务声明的括号内,将根据稍后描述的算法来处理授权请求中的参数。授权服务时(例如,当找不到匹配属性时)的某些操作取决于默认配置的方式。以下声明将默认值从deny更改为允许该用户和服务。

1
user = lol { service = shell { default attribute = permit } }

注意:此指令必须出现在服务声明中的其他任何指令之前。

注意:对于命令授权(与此处讨论的服务授权相反),需要指定deny .*或permit .*。因为正则表达式的最后一行匹配以创建默认行为。

Authorizing EXEC (SHELL) Startup:

每当Shell启动时,您都可以提供一些参数,例如自动命令,回拨字符串或连接访问列表(acl)。在以下示例中,在NAS上启动exec时,acl为4的将返回到NAS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
user=fred {

# this following line permits an exec to start and permits
# all commands and services by default

default service = permit

service = shell {
# When an exec is started, its connection access list will be 4.
# It also has an autocmd.
set acl = 4
set autocmd = "telnet foobar"

cmd = telnet {
# allow all fred's telnet commands except telnet to 131.108.13.*
deny 131\.108\.13\.[0-9]+
permit .*
}
}
}

注意:指定自动命令或任何其他exec服务是EXEC AUTHORIZATION的一部分。为了使其正常工作,您还必须在NAS上配置exec授权,例如

1
2
3
> aaa authorization exec authorlist group tacacs+ local
> aaa authorization commands 15 cmdlist group tacacs+ local
>

并最终在线上:

1
2
3
> authorization commands 15 cmdlist
> authorization exec authorlist
>

与认证一样,您可以使用命名的授权列表,也可以仅使用默认列表。

Authorizing EXEC, SLIP, PPP and ARAP services:

对EXEC,SLIP,PPP和ARAP服务的授权与命令授权完全不同。

授权这些服务时,NAS发送包含多个属性值(AV)对的请求,每个对具有以下形式:attribute=value .

(注意:在调试期间,您可能会看到分隔符为*而不是=符号的AV对,这意味着一对中的值是可选的。=符号表示必填值。*表示可选值)。

例如,使用131.108.12.44地址启动PPP / IP的用户将使用以下AV对生成请求:

1
2
3
service=ppp
protocol=ip
addr*131.108.12.44

您可以使用NAS调试命令:

1
debug aaa authorization

查看NAS正在使用哪些授权AV对。注意:如果您不在路由器控制台上,则还需要发出terminal monitor命令以查看调试输出。

授权过程:

授权单个会话可能导致将多个请求发送到守护程序。例如,为了授权拨入PPP用户使用IP,将从NAS发出以下授权请求:

  1. 将使用AV对service = ppp,protocol = ip发出从执行程序启动PPP的初始授权请求(注意:如果您是自动选择PPP,则此初始请求将被省略,因为您尚不知道用户名)

    确认完成了此请求,以查找无法进行地址协商的哑PPP(或SLIP)客户端的地址。相反,他们希望您通过文本消息(例如“输入PPP。您的地址为1.2.3.4”)告诉他们在PPP启动之前使用哪个地址。他们依靠从消息中解析此地址来知道其地址。

  2. 接下来,从PPP子系统发出授权请求,以查看PPP的LCP层是否得到授权。可以在此时设置LCP参数(例如回调)。该请求包含AV对service = ppp,protocol = lcp。

  3. 接下来,使用AV对service = ppp,protocol = ipcp发出启动PPP的IPCP层的授权请求。守护程序返回的所有参数都将被缓存。

  4. 接下来,在PPP的地址协商阶段,每次远程对等方请求一个特定的地址时,如果该地址不在步骤3中获得的缓存中,则会进行新的授权请求,以查看对等方请求的地址是否允许。该步骤可以重复多次,直到双方在远程对等方的地址上达成一致,或者直到NAS(或客户端)决定他们永远都不会达成一致,然后关闭PPP。

授权取决于认证:

由于我们非常依赖授权请求中的用户名来确定要分发的地址等,因此了解PPP用户的用户名来自何处非常重要。通常有两种可能的来源:

  1. 您通过使用户登录到exec来强制用户进行认证,并在授权请求中使用该登录名。默认情况下,此用户名不会传播到PPP。为此,通常需要配置if-need方法,例如:

    1
    2
    aaa authentication login default tacacs+
    aaa authentication ppp default if-needed
  2. 或者,您可以运行认证协议PAP或CHAP(首选CHAP)来标识用户。如果执行此操作,则不需要显式的登录步骤(因此,如果使用自动选择,则这是唯一的可能性)。当然,在您看到第一个LCP授权请求之前,已完成此认证。通常,您可以通过以下方式进行配置:

    1
    2
    3
    aaa authentication ppp default tacacs+ 
    int async 1
    ppp authentication chap

如果您省略这两种认证方案中的任何一个,您将开始看到缺少用户名的授权请求。

配置service授权:

AV对列表放置在守护程序的配置文件中,以授权服务。守护程序会将每个NAS AV对与其已配置的AV对进行比较,并允许或拒绝该服务。如果允许该服务,则守护程序可以在将AV对返回到NAS之前添加,更改或删除AV对,从而限制了允许用户执行的操作。

授权算法:

下面给出了守护程序根据NAS发送的列表处理其配置的AV对的完整算法。 查找此服务(和协议)的用户(或组)条目,然后查找从NAS发送的每个AV对:

  1. 如果来自NAS的AV对是必选的:
    1. 在用户的强制列表中查找确切的属性,值匹配。如果找到,则将AV对添加到输出中。
    2. 如果不存在完全匹配项,请在用户的可选列表中查找第一个属性匹配项。如果找到,则将NAS AV对添加到输出中
    3. 如果不存在任何属性匹配项,那么如果默认设置为拒绝,则拒绝该命令,或者,
    4. 如果默认值为允许,则将NAS AV对添加到输出中。
  2. 如果来自NAS的AV对是可选的:
    1. 在用户的强制性列表中查找确切的属性,值匹配。如果找到,则将DAEMON的AV对添加到输出。
    2. 如果找不到,请在用户的强制性列表中查找第一个属性匹配。如果找到,则将DAEMON的AV对添加到输出。
    3. 如果不存在强制匹配项,则在守护程序的可选AV对中查找确切的属性,值对匹配。如果找到,则将DAEMON的匹配AV对添加到输出中。
    4. 如果不存在完全匹配,请在守护程序的可选AV对中找到第一个属性匹配。如果找到,则将DAEMON的匹配AV对添加到输出中。
    5. 如果没有找到匹配项,请删除AV对,如果默认设置为deny,或者
    6. 如果默认设置为允许,则将NAS AV对添加到输出中。
  3. 处理完所有AV对之后,对于每个必需的DAEMON AV对,如果输出列表中没有属性匹配,则添加AV对(但为每个必需属性仅添加一个AV对)。
递归授权:

请记住,授权对于组也是递归的。因此,如果将用户放置在组中,则守护程序将在用户声明中找不到授权参数的情况下在组中查找授权参数。

授权配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
host = 0.0.0.0/0 {
key = "your key here"
}

group = admin {
# group members who have no expiry date set will use this one
valid until = 1997-01-01
service = shell {
default cmd = permit
}
}

user=fred {
login = crypt mEX027bHtzTlQ
member = admin
valid until = 2005-05-23

service = shell {
# When Fred starts an exec, his connection access list is 5
set acl = 5

# We require this autocmd to be done at startup
set autocmd = "telnet foo"

# All commands except show system are denied for Fred
cmd = show {
# Fred can run the following show command
permit system
deny .
}
}

service = ppp {
protocol = lcp
protocol = ip {
# Fred can run IP over PPP only if he uses one
# of the following mandatory addresses. If he
# supplies no address, the first one here will
# be mandated
set addr=131.108.12.11
set addr=131.108.12.12
set addr=131.108.12.13
set addr=131.108.12.14

# Fred's mandatory input access list number is 101
set inacl=101

# We will suggest an output access list of 102,
# but the NAS may choose to ignore or override it
optional outacl=102
}
}

service = slip {
default protocol = permit
# Fred can run SLIP. When he does, he will have to use
# these mandatory access lists
set inacl=101
set outacl=102
}
}

user = wilma {
login = crypt mEX027bHtzTlQ
member = admin
}

在NAS上配置授权:

如果未在NAS上显式配置授权,则不会发生授权,即有效地,一切都被允许。请注意,这与守护程序发生的情况相反,在守护程序中,默认情况下拒绝任何未明确允许的内容。

要在NAS上配置命令授权,请发出以下NAS配置命令:

1
2
3
aaa authorization commands 15 cmdlist group tacacs+ local
aaa authorization commands 1 cmdlist
aaa authorization commands 15 cmdlist

这将使NAS为所有1级(普通用户)和15级(特权级)命令发送TACACS +请求。

或者,或者此外,您可能还需要配置以下内容:

1
aaa authorization commands 1 group tacacs+ if-authenticated

这将对级别1(用户级别的命令)使用TACACS +授权,但是如果出现问题,您可以关闭TACACS +服务器,然后将授权给任何已认证的人。

以下守护程序配置应足以确保您始终可以以用户名admin(使用适当的密码)登录并以该用户身份运行任何命令:

1
2
3
4
5
user = admin {
default service = permit
service = shell { default cmd = permit }
login = crypt kppPfHq/j6gXs
}

MAVIS Backends(MAVIS后端)

该发行版附带各种MAVIS模块,其中外部模块可能是最有趣的,因为它与简单的Perl脚本进行交互以对请求进行认证和授权。您可以在mavis / perl目录中找到示例脚本。请仔细查看它们,因为您可能(或将需要)执行一些琐碎的自定义操作,以使其与您的本地环境相匹配。

您应该真正看看MAVIS文档。它还提供了RADIUS和PAM认证的示例。

LDAP Backends:

mavis_tacplus_ldap.pl是外部模块的认证/授权后端。它连接到各种LDAP服务器,例如OpenLDAP,Fedora DS和Active Directory。它的行为由一系列环境变量控制:

下表为LDAP后端环境变量:

Variable Description
LDAP_SERVER_TYPE One of: generic, tacacs_schema, microsoft.Default: tacacs_schema
LDAP_HOSTS LDAP_HOSTS LDAP URL或IP地址或主机名的以空格分隔的列表,例如:"ldap01 ldap02", "ldaps://ads01:636 ldaps://ads02:636"
LDAP_SCOPE LDAP搜索范围 (base, one, sub)Default: sub
LDAP_BASE LDAP服务的基本DN,例如: dc=example,dc=com
LDAP_FILTER LDAP搜索过滤器. Defaults:for LDAP_SERVER_TYPE=generic:"(uid=%s)"for LDAP_SERVER_TYPE=tacacs_schema:"(&(uid=%s)(objectClass=tacacsAccount))"for LDAP_SERVER_TYPE=microsoft:"(&(objectclass=user)(sAMAccountName=%s))"
LDAP_FILTER_CHPW LDAP search filter for password changes. Defaults:for LDAP_SERVER_TYPE=generic:"(uid=%s)"for LDAP_SERVER_TYPE=tacacs_schema:"(&(uid=%s)(objectClass=tacacsAccount)(!(tacacsFlag=staticpasswd)))"for LDAP_SERVER_TYPE=microsoft:"(&(objectclass=user)(sAMAccountName=%s))"
LDAP_USER 如果服务器不允许匿名搜索,则用于LDAP绑定的用户。.Default: unset
LDAP_PASSWD Password for LDAP_USERDefault: unset
AD_GROUP_PREFIX 以该前缀开头的AD组将用作用户的TACACS +组成员身份。 AD_GROUP_PREFIX的值将从组名称中删除。示例:将AD_GROUP_PREFIX设置为tacacs(这实际上是默认值),TacacsNOC的AD组成员身份会将用户分配给NOC TACACS +组。请注意,TACACS +组名称区分大小写。
REQUIRE_AD_GROUP_PREFIX 如果设置,则用户需要属于AD_GROUP_PREFIX组之一。.Default: unset
USE_TLS 如果设置,则服务器需要支持start_tls.Default: unset
FLAG_CHPW 允许通过此后端更改密码.Default: unset
FLAG_PWPOLICY 尝试实施简单的密码策略。.Default: unset
FLAG_CACHE_CONNECTION 保持与LDAP服务器的连接打开。.Default: unset
FLAG_FALLTHROUGH 如果在LDAP中搜索用户失败,请尝试下一个MAVIS模块(如果有)。Default: unset
FLAG_USE_MEMBEROF 使用memberOf属性确定组成员身份。将LDAP_SERVER_TYPE设置为Microsoft暗示了这一点。如果您在启用memberof overlay的情况下运行OpenLDAP,则可以使用。Default: unset

LDAP Custom Schema Backend:

对于将LDAP_SERVER_TYPE设置为tacacs_schema的程序,程序期望LDAP服务器支持实验性ldap.schema,包括在OpenLDAP和Fedora-DS中。模式文件位于mavis / perl目录中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
dn: uid=marc,ou=people,dc=example,dc=com
uid: marc
cn: Marc Huber
objectClass: posixAccount
objectClass: inetOrgPerson
objectClass: shadowAccount
objectClass: tacacsAccount
shadowMax: 10000
uidNumber: 1000
gecos: Marc Huber
givenName: Marc
sn: Huber
gidNumber: 500
shadowLastChange: 14012
loginShell: /bin/bash
homeDirectory: /Users/marc
mail: marc@example.com
userPassword:: abcdefghijklmnopqrstuvwxyz=
tacacsClient: 192.168.0.0/24
tacacsClient: management
tacacsMember: readonly@172.16.5.0/24
tacacsMember: readwrite@nasgroup
tacacsProfile: { valid until = 2010-01-30 chap = clear ahzoi5Ue }

Active Directory Backend:

如果LDAP_SERVER_TYPE设置为microsoft,则脚本将后端到AD服务器。样本配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
id = spawnd {
listen = {
port = 49
}
spawn = {
instances min = 1
instances max = 10
}
background = yes
}

id = tac_plus {
access log = /var/log/tacacs/%Y/%m/%d/access.log
accounting log = /var/log/tacacs/%Y/%m/%d/acct.log

mavis module = external {
# Optionally:
# script out = {
# # Require group membership:
# if (undef($TACMEMBER) && $RESULT == ACK) set $RESULT = NAK
#
# # Don't cache passwords:
# if ($RESULT == ACK) set $PASSWORD_ONESHOT = 1
# }

setenv LDAP_SERVER_TYPE = "microsoft"
# setenv LDAP_HOSTS = "ldaps://ads01:636 ldaps://ads02:636"
setenv LDAP_HOSTS = "ads01:3268 ads02:3268"
setenv LDAP_SCOPE = sub
setenv LDAP_BASE = "dc=example,dc=com"
setenv LDAP_FILTER = "(&(objectclass=user)(sAMAccountName=%s))";
setenv LDAP_USER = tacacs@example.com
setenv LDAP_PASSWD = Secret123
setenv AD_GROUP_PREFIX = tacacs
# setenv REQUIRE_AD_GROUP_PREFIX = 1
setenv USE_TLS = 0
exec = /usr/local/lib/mavis/mavis_tacplus_ldap.pl
}

login backend = mavis
pap backend = mavis

host = world {
address = ::/0
welcome banner = "Welcome\n"
key = cisco
}

host = helpdesklab {
address = 192.168.34.16/28
}

# A user will be in the "admin" group if he's member of the
# corresponding "tacacsadmin" ADS group.

group = admin {
default service = permit
service = shell {
default command = permit
default attribute = permit
set priv-lvl = 15
}
}

# A user will be in the "helpdesk" group if he's member of the
# corresponding "tacacshelpdesk" ADS group:

group = helpdesk {
default service = permit
service = shell {
default command = permit
default attribute = permit
set priv-lvl = 1
}
enable = deny
member = admin@helpdesklab
}
}

通用LDAP后端:

如果将LDAP_SERVER_TYPE设置为generic,则脚本不需要对LDAP服务器进行任何修改,而只对配置文件中定义的用户进行认证(使用login = mavis、pap = mavis或password = mavis声明)。此后端不进行任何授权。

PAM后端:

使用可插拔认证模块( Pluggable Authentication Modules:)的示例配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
id = spawnd { listen = { port = 49 } }

id = tac_plus {
mavis module = groups {
resolve gids = yes
groups filter = /^(guest|staff)$/
script out = {
# copy the already filtered UNIX group access list to TACMEMBER
eval $GIDS =~ /^(.*)$/
set $TACMEMBER = $1
}
}
mavis module = external {
exec = /usr/local/sbin/pammavis pammavis -s sshd
}
user backend = mavis
login backend = mavis
host = global { address = 0.0.0.0/0 key = cisco }

group = staff {
service = shell {
default command = permit
set priv-lvl = 15
}
}
group = guest {
service = shell {
default command = deny
set priv-lvl = 15
cmd = show { permit .* }
}
}
}

系统密码后端:

mavis_tacplus_passwd.pl根据您的本地密码数据库进行认证。遗憾的是,要使用这个功能,脚本可能必须以root身份运行,因为它需要访问加密的密码。主和辅助UNIX组成员关系将映射到TACACS+组。

mavis_tacplus_opie.pl基于mavis_tacplus_passwd.pl,但使用OPIE一次性密码进认证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
id = spawnd {
listen = { port = 49 }
}

id = tac_plus {
mavis module = external {
exec = /usr/local/lib/mavis/mavis_tacplus_opie.pl
}
login backend = mavis chalresp
host = global { address = 0.0.0.0/0 key = cisco }
group = staff {
service = shell {
default command = permit
set priv-lvl = 15
}
}
user = user1 { password = mavis member = staff }
user = user2 { password = clear pass2 member = staff }
}

Shadow Backend:

可以使用mavis_tacplus_shadow.pl将用户密码排除在tac_plus configuration文件之外,从而允许用户通过密码更改对话框更改密码。密码存储在一个辅助的/etc/shadow类ASCII文件中,每行一个用户:

1
username:encryptedPassword:lastChange:minAge:maxAge:reserved

lastChange是上一次更改密码自1970-01-01以来的天数,minAge和maxAge确定密码是否可以/不需要更改。将lastChange设置为0强制在第一次登录时更改密码。

Example shadow file:

1
2
3
marc:$1$q5/vUEsR$jVwHmEw8zAmgkjMShLBg/.:15218:0:99999:
newuser:$1$pQtQsMuj$GKpIr5r2GNaZNfDfnCBtw.:0:0:99999:
test:$1$pQtQsMuj$GKpIr5r2GNaZNfDfnCBtw.:15218:1:30:

示例守护程序配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
id = tac_plus {
...
mavis module = external {
setenv SHADOWFILE = /path/to/shadow
# setenv FLAG_PWPOLICY=y
# setenv ci=/usr/bin/ci
exec = /usr/local/lib/mavis/mavis_tacplus_shadow.pl
}
...
login backend = mavis chpass
...
user = marc {
login = mavis
...
}
...
}
...

RADIUS Backend:

mavis_tacplus_radius.pl针对RADIUS服务器进行认证。除非设置了RADIUS_GROUP_ATTR环境变量,否则不会进行任何授权。例如,如果配置文件中有静态用户帐户定义,那么这可能很有用,但是应该用RADIUS验证身份验证密码。在用户配置文件中使用login = mavis或password = mavis语句来执行此操作。

示例配置:

1
2
3
4
5
6
mavis module = external {
exec = /usr/local/lib/mavis_tacplus_radius.pl
setenv RADIUS_HOST = 1.2.3.4:1812
setenv RADIUS_SECRET = "mysecret"
setenv RADIUS_GROUP_ATTR = Some-Radius-Attribute
}

如果安装了Authen::Radius Perl模块,则使用RADIUS_GROUP_ATTR指定的Radius属性的值来创建一个TAC_PROFILE定义,该定义使用属性值作为组成员。例如,Administrator的属性值{ member = Administrator }将导致配置文件启用授权并在配置文件中省略对静态用户的需求。

请记住,这仅在以下情况下有效:

  • 使用单连接(single-connection)
  • mavis缓存超时设置为足够高的值,可以覆盖用户(预期)的最大登录时间。

实验性后端:

mavis_tacplus_sms.pl是一个示例(skeleton)脚本,用于通过SMS后端发送一次性密码。

错误处理:

如果后端脚本由于外部问题(例如LDAP服务器不可用)而失败,则您的路由器可能会也可能不会退回到本地身份验证(如果已配置)。可能的情况是,后备功能不起作用。如果您仍然希望在这种情况下能够通过TACACS +进行认证,则可以使用非MAVIS用户进行身份验证,该用户仅在出现后端错误时才有效:

1
2
3
4
5
6
7
8
9
10
...
# set the time interval you want the user to be valid if the backend fails:
authentication fallback period = 60 # that's actually the default value
...
# add a local user for emergencies:
user = cisco {
...
fallback-only
...
}

为了表明后备模式(fallback mode )实际上处于活动状态,可以向用户显示不同的登录提示:

1
2
3
4
5
6
host = ... {
...
welcome banner = "Welcome\n"
welcome banner fallback = "Welcome\nEmergency accounts are currently enabled.\n"
...
}

fallback可以基于每个主机全局启用/禁用。默认启用。

1
2
3
4
5
6
authentication fallback = permit
host = ... {
...
authentication fallback = deny
...
}

Debugging

Debugging Configuration Files(调试配置文件):

创建配置文件时,使用tac_plus的-P标志检查它们的语法很方便。例如:

1
tac_plus -P config-file

将语法检查配置文件并在终端上打印任何错误消息。

Trace Options(跟踪选项):

跟踪(或调试)选项可以在全局,主机,用户和组上下文中指定。当前的调试级别是所有这些的组合(读:OR)。通用语法为:

1
debug = option ...

例如,以一种可预测的方式获得命令授权工作可能是棘手的——NAS发送给守护进程的确切属性可能取决于IOS版本,通常可能不符合您的期望。如果正则表达式不能工作,添加debug = REGEX 在适当的情况下,守护程序可能会将一些有用的信息记录到syslog中。

可以指定多个跟踪选项。例:debug = REGEX CMD

调试和跟踪值表中汇总了可用的调试选项。

Table 3. Debug and Trace Values

Bit Value Name Description
0 1 PARSE Configuration file parsing
1 2 AUTHOR Authorization related
2 4 AUTHEN Authentication related
3 8 ACCT Accounting related
4 16 CONFIG Configuration related
5 32 PACKET Packet dump
6 64 HEX Packet hex-dump
7 128 LOCK File locking
8 256 REGEX Regular expressions
9 512 ACL Access Control Lists
10 1024 RADIUS unused
11 2048 CMD Command lookups
12 4096 BUFFER Buffer handling
13 8192 PROC Procedural traces
14 16384 NET Network related
15 32768 PATH File system path related
16 65536 CONTROL Control connection related
17 131072 INDEX Directory index related
18 262144 AV Attribute-Value pair handling
19 524288 MAVIS MAVIS related
20 1048576 LWRES DNS related
31 2147483648 NONE Disable debugging

其中一些调试选项未使用,不会触发任何输出。

img

Railroad diagram: Debug

FAQ(Frequently Asked Questions)

是否有任何图形用户界面?

没有,除非您最喜欢的文本编辑器符合条件。配置语法过于复杂和灵活,无法使用GUI覆盖。如果您正在寻找一种管理用户数据库的方法,那么可以看看Webmin,ActiveDirectory等。将它们用作认证/授权后端很简单。

如何使用MySQL后端?

除非您愿意自己编写SQL后端,否则您不会这样做。这其实并不难,但显然很大程度上取决于数据库结构,没有足够通用的方法可以将您从这一步中解放出来。只要看一看这个发行版附带的LDAP Perl脚本就可以了。如果您对Perl和SQL数据库非常熟悉,那么编写后端将是小菜一碟。

我正在使用单连接功能。如何强制路由器关闭与TACACS +服务器的TCP连接?

在IOS上,show tcp brief将显示TCP连接。搜索终止于您服务器的服务器,然后使用clear tcp tcb …将其杀死。示例:

1
2
3
4
5
6
7
8
9
10
Router#sho tcp brief | incl 10.0.0.1.49  
633BB794 10.0.0.2.17326 10.0.0.1.49 ESTAB
6287E4C4 10.0.0.2.24880 10.0.0.1.49 ESTAB
Router#clear tcp tcb 633BB794
[confirm]
[OK]
Router#clear tcp tcb 6287E4C4
[confirm]
[OK]
Router#

守护程序是否需要的DNS?

不,DNS不是必需的。但是,您可以在NAC ACL列表中使用DNS反向映射,前提是该软件使用lwres支持进行编译并且相应的lwresd正在运行。

当我已经登录并通过认证时,为什么由于请求中没有用户名而导致PPP授权失败?

使用aaa authentication ppp default group tacacs+, ppp认证将覆盖早期的登录认证。如果ppp认证失败,用户名将变为空白。将配置更改为 aaa authentication ppp default if-needed group tacacs+修复了这个问题。

有什么方法可以避免在配置文件中使用ARAP和CHAP密钥的明文版本?

CHAP和ARAP要求服务器知道明文密码(或者等价的,服务器可以从中生成明文密码)。请注意,这是CHAP和ARAP定义的一部分,而不是某个深夜喝了太多咖啡的思科工程师的想法。

如果我们在数据库中加密了CHAP和ARAP密码,那么我们需要在周围保留一个密钥,以便在需要CHAP或ARAP时服务器可以解密它们。因此,这只是一个轻微的混淆,并没有比原来的方案更安全。

在扩展的TACACS中,CHAP和ARAP 密码与密码文件分离,因为密码文件可能是系统密码文件,因此全世界都可读。但是对于TACACS+的本机数据库,则没有这样的要求,所以我们认为最好的解决方案是读取保护文件。注意,这与Kerberos服务器有相同的问题。如果您在Kerberos服务器上的安全性受到威胁,那么您的数据库是完全开放的。Kerberos确实对数据库进行了加密,但是如果希望服务器自动重新启动,那么无论如何都必须在文件中“kstash”密钥,这样就又回到了相同的安全问题。

因此,在安全服务器上存储明文密码确实是CHAP和ARAP协议的绝对要求,而不是由TACACS+强加的。

对于新的TACACS+协议修订的方案选择,NAS将询问信息发送给TACACS+守护进程,守护进程使用明文密码生成响应并返回响应。

TACACS+协议包含了ARAP和CHAP的特定协议知识(此版本的守护进程实现不再支持SENDPASS机制)。

注意,以上内容不适用于PAP。您可以对入站PAP密码DES-或md5进行加密,因为您只需要验证主体提供的密码是否正确。

典型的登录登录顺序如何完成?

  1. NAS发送START包给daemon。
  2. Daemon发送GETUSER包含登录提示给NAS。
  3. NAS提示用户输入用户名
  4. NAS发送数据包给daemon
  5. Daemon发送GETPASS包含密码提示给NAS
  6. NAS提示用户输入密码
  7. NAS发送数据包给daemon
  8. Daemon发送accept, reject或error给NAS。

default service = permit”实际上是做什么的?

当进入一个请求来授权exec启动,或ppp(使用协议lcp、ip、ipx),或slip,或arap或一个特定命令时,守护进程为用户(或用户所属的组)寻找匹配的声明。

  • 对于exec启动,它将查找service = shell。
  • 对于PPP,它将查找service = ppp和protocol = lcp,ip,ipx之一。
  • 对于SLIP,必须有一个service = slip,对于ARAP,必须有一个service = arap子句。
  • 对于commands,必须有匹配的cmd = cmdname或默认的cmd =permit定义。
  • 如果未找到,则授权将失败,除非您说default service = permit.。

如何使PAP工作?

请避免使用PAP,它是太不安全的。如果必须使用它,则可以为每个用户指定PAP密码以及ARAP和CHAP密码。

对于outbound PAP,您被迫向远程主机发送密码以识别自己的身份,现在有一个单独的opap指令,例如:opap = clear OOOO 使用此设置outbound PAP密码。它必须是明文密码。

密码:

使用与任何inbound 密码相同的outbound PAP密码是非常糟糕的做法。因此,一个“全局”密码,定义为password = clear…语句,不适用于outbound PAP,只适用于inbound PAP,双向CHAP和ARAP。

如何仅通过IP地址拒绝从通用服务器进行的远程登录,即命令是10.0.1.6而不是telnet 10.0.1.6?

限制telnet访问的最佳方法是通过access class命令应用出站访问列表(或者等效地,通过“acl”avpair)。NAS配置命令:

1
access-class n out

例如,应用预定义的标准IP访问列表(其中n是从1到99的数字)来管理来自NAS的telnet访问。

例如。以下配置命令允许“仅”从NAS上的line 1到网络192.85.55.0上的主机的出站Telnet访问:

1
2
3
access-list 12 permit 192.85.55.0 0.0.0.255
line 1
access-class 12 out

注意:您必须在NAS上定义访问列表。只有这样,您才能使用acl avpair将其应用于用户拨入的线路。

或者,您可以尝试在相关线路上配置transport preferred none。这将迫使用户总是键入telnet 10.0.1.6,以便通过telnet从NAS中导出。然后可以对该命令应用命令授权来限制它。

我在NAS本地数据库中配置了自动命令,我正在使用aaa authentication local-override 自动命令无效,但用户名/密码有效。为什么?

local-override仅适用于本地数据库的认证部分,因此,如果要为此用户使用自动命令,还需要执行以下操作:aaa authorization exec local if-authenticated

如果存在一个本地数据库条目,它将使用本地数据库条目,否则将允许通过认证用户,否则将失败。

我们没有像认证那样的aaa authorization local-override。与认证不同,用于授权的本地方法在某种程度上等效于 local-override。

只能在全局范围内启用TACACS +吗?

您可以全局打开TACACS +,但随后可以将各个线路的行为更改为所需的任何方式,例如:

1
2
3
4
5
6
7
8
9
aaa authentication login default tacacs+ none
aaa authentication login oldstyle line
aaa authentication login none none
line 1 16
login authentication default
line vty 0 4
login authentication oldstyle
line 0
login authentication none

请注意,不幸的是,您还不能(尚未)对选定的行和接口应用不同的授权。

我有运行PPP的租用线路,并且还配置了AAA授权,因此租用线路上的授权失败。我该怎么办?

由于您还不能按行配置授权,因此必须在运行PPP的租用线路上打开认证,并配置TACACS +服务器,以便它可以正确授权这些线路(lines)。

要求更高的替代方法是修改TACACS +服务器源代码,以允许从端口“ SerialXXX”进入的任何授权都能够成功。

第三种可能性是不要在这些线路上使用PPP,例如请改用HDLC。 HDLC不需要认证或授权。

TACACS +用户名和密码可以包含多少个字符?

简短的答案是用户名为31个字节,如果为明文,则最多为254个字节的密码(如果密码为DES加密,则为8个字节)。

最长答案是,Cisco NAS会分配1024个字节的缓冲区,因此这是您可以输入的最大数量,以响应NAS提示。

但是协议规范允许认证数据包中的用户名或密码长度字段只有一个字节,因此只能将这些字符的前255个发送到守护程序。

现在,如果它是DES加密密码,那么按照crypt的常见unix实现,只有前8个字节是有效的

如何限制用户可以拥有的会话数?

使用此版本的守护程序,您将无法使用。

如何通过TACACS +在接口上配置超时?

在授权过程中,TACACS +可能会设置某些每个用户/每个接口的超时时间。从11.0开始,您可以设置arap会话超时和exec超时。从11.1开始,您还可以设置exec空闲超时。

当接口空闲一段时间后,空闲超时会终止连接(这相当于Cisco IOS配置指令的“会话超时”)。其他超时是绝对的。当然,由TACACS+设置的任何超时只适用于当前连接。

1
2
3
4
5
6
7
user = lol {
login = clear foobar
service = shell {
set idletime = 5 # disconnect lol if there is no traffic for 5 minutes
set timeout = 60 # disconnect lol unconditionally after one hour
}
}

您还需要在NAS上为上述超时配置exec授权,例如 aaa授权执行程序默认组tacacs +

1
aaa authorization exec default group tacacs+

请注意,这些超时仅适用于异步线路,当前不适用于ISDN。

还请注意,您不能将授权if-authenticated选项与这些参数一起使用,因为如果用户已成功进行认证,则该选项将跳过授权。

Canned Configurations

以下是一些入门的配置:

Login Authentication,登陆认证:

仅用于登录认证的基础配置。这允许用户fred使用密码abcdef登录。如果TACACS +服务器死亡,则将启用密钥用作登录密码。

Daemon:

1
2
3
4
5
6
7
8
9
id = spawnd {
listen = { port = 49 }
}
id = tac_plus {
host = any { key = "some key" address = 0.0.0.0/0 }

# repeat as necessary for each user
user = fred { login = clear abcdef }
}

NAS:

1
2
3
4
5
6
aaa new-model
enable secret foobar
! use TACACS+. If server dies, use the enable secret password
aaa authentication login default group tacacs+ enable
tacacs-server host ...
tacacs-server key some key

Command Authorization,命令授权:

这将允许用户fred使用密码abcdef登录,并运行特权(级别15)命令write terminal and configure。所有其他特权命令将被拒绝。

NAS配置行中的“ none”关键字表示,如果TACACS +服务器死亡,则将允许任何命令。

Daemon:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
id = spawnd {
listen = { port = 49 }
}
id = tac_plus {
host = any { key = "some key" address = 0.0.0.0/0 }

# repeat as necessary for each user
user = fred {
login = clear abcdef
service = shell {
cmd = write { permit terminal }
cmd = configure { permit .* }
}
}
}

NAS:

1
2
3
4
5
aaa new-model
! all level 15 (privileged commands). If server dies, allow everything
aaa authorization commands 15 default group tacacs+ none
tacacs-server host 10.1.1.1
tacacs-server key some key

Network Access Authorization,网络访问授权

此配置允许fred使用密码abcdef登录到line 1(或使用chap身份验证登录并运行ppp。chap密码为lab。

Daemon:

1
2
3
4
5
6
7
8
9
10
11
12
13
id = spawnd {
listen = { port = 49 }
}
id = tac_plus {
host = any { key = "some key" address = 0.0.0.0/0 }

# repeat as necessary for each user
user = fred {
login = clear abcdef
chap = clear lab
service = ppp { protocol = ip { set addr=1.0.0.2 } }
}
}

NAS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
aaa new-model
! authenticate exec logins (if not autoselecting)
aaa authentication login default group tacacs+
! authorize network services via TACACS+
aaa authorization network default group tacacs+
! use TACACS+ for authenticating ppp users
aaa authentication ppp default group tacacs+
tacacs-server host 10.1.1.1
tacacs-server key some key
interface Async1
ip address 1.0.0.1 255.0.0.0
async default ip address 172.21.14.55
encapsulation ppp
async dynamic address
async mode interactive
! use chap to authenticate ppp users
ppp authentication chap
line 1
! need "modem inout" here and flow control if using a modem

ARAP:

Daemon:

1
2
3
4
5
6
7
8
9
10
11
id = spawnd {
listen = { port = 49 }
}
id = tac_plus {
host = any { key = "some key" address = 0.0.0.0/0 }

user = lol {
arap = clear arapSecret
service = arap
}
}

NAS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
aaa new-model
aaa authentication arap default group tacacs+
aaa authorization network default group tacacs+
aaa accounting network default start-stop group tacacs+
!
appletalk routing
arap network ...
!
interface Ethernet0
appletalk cable-range ...
appletalk zone ...
!
tacacs-server host ...
tacacs-server key ...
!
line 1
location a modem
modem answer-timeout 0
modem InOut
autoselect arap
autoselect during-login
arap enable
speed ...
flowcontrol hardware

Callback:

Daemon:

用户名foobar的远程TACACS +服务器配置文件条目的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
id = spawnd {
listen = { port = 49 }
}
id = tac_plus {
host = any { key = "some key" address = 0.0.0.0/0 }

user = foobar {
arap = clear AAAA
login = clear LLLL
chap = clear CCCC
pap = clear PPPP
opap = clear OOOO
service = ppp {
default protocol = permit
protocol = lcp {
set callback-dialstring=123456
}
}
service = arap {
protocol = atalk {
set callback-dialstring=2345678
}
}
service = shell {
set callback-dialstring=3456789
set callback-line=7
set nocallback-verify=1
}
}
}

NAS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
aaa new-model
tacacs-server host XX.XX.XX.XX
tacacs-server key fookey
aaa accounting exec wait-start tacacs+
aaa accounting network wait-start tacacs+

! Example of AAA configuration for Exec:
aaa authentication login execcheck tacacs+
aaa authorization network tacacs+
service exec-callback

line 4
login authentication execcheck

! Example of AAA configuration for ARAP:
aaa authentication arap arapcheck tacacs+
aaa authorization network tacacs+
arap callback

line 4
arap authentication arapcheck

! Example of AAA-specific configuration for PPP callback:
aaa new-model
aaa authentication ppp pppcheck tacacs+
aaa authorization network tacacs+

int async 6
ppp authentication chap pppcheck
ppp callback accept

其他文章:


参考资料:

http://www.pro-bono-publico.de/projects/tac_plus.html#AEN9

https://github.com/facebookarchive/tac_plus

https://networklessons.com/uncategorized/how-to-install-tacacs-on-linux-centos

https://www.tecmint.com/installation-and-configuration-of-tacacs-using-cisco-on-debian/

坚持原创技术分享,您的支持将鼓励我继续创作!