Freeradius and Cisco ASAs - Proper separation of roles!


I wrote some time ago about separating read-only access from admin access to Cisco ASAs using Microsoft NPS. It worked in theory, but a problem was found that an AD user who was not a member of either OU could still authenticate to the ASA using ASDM at level 15. Clearly this was less than ideal. Check out the link though as it shows how to set up the ASA to use Radius and we'll need that in a while.

I bounced around some more ideas, tested things out using Microsoft NPS, and even tried TACACS using Tac-plus. Still no dice. I went back to the idea of using Radius, mainly because of the fact that I didn't want to have to run two systems to do the same thing, NPS got us most of the way there, TACACS would probably have finished the job, but requires a lot more investment in time, knowledge and money. Coupled with the fact that the IPS modules in our ASAs only support RADIUS I knew it was time to head back to the RADIUS idea and try and put this to bed.

Microsoft NPS doesn't cut the mustard though. Yes it's a good product, but clearly not the right product for this scenario.

Freeradius on the other hand offered something new, and I stumbled across the idea of using it from this very excellent post here. Our set up is slightly different though, as we are using Microsoft AD as the LDAP backend, and require the use of AD groups as well as nesting of access control.

To explain, we have two users; npstest is a read-only account. It should have access to the ASA through SSH and through ASDM, but only at a maximum of level 3. It is a member of the AD group "sec-fw-readonly". My own account should have full access on both SSH and ASDM and is a member of "sec-fw-administrator".

We start with a Centos box and install freeradius using the command:
yum install freeradius*
Once free radius is installed we need to head to the folder /etc/raddb/ and from there into the modules directory (/etc/raddb/modules). The first file we neeed to edit is the ldap file (vi ldap) and set our details for connecting to the AD server:
server = "adserver.domain.local"
identity = "cn=ldapreadonly,ou=Service Accounts,dc=domain,dc=local"
password = passw0rd
basedn = "dc=domain,dc=local"
filter = "(&(objectclass=user)(objectcategory=user)(userPrincipalName=%{%{Stripped-User-Name}:-%{User-Name}}*))"
groupmembership_attribute = "memberOf"
The first line specifies the domain controller to connect to, and the next line specifies the account to use, the third line is the password for that account. The basedn is where freeradius should start searching for user accounts, and the filter does some funky mapping of AD attributes to freeradius attributes. The groupmembership_attribute will be needed for the reading of AD groups which we will need later on.

Lastly for this file is to uncomment these two lines:
chase_referrals = yes
rebind = yes
If you don't uncomment those then you will get an "operations error" message when trying to search.

Next we must go back a level and into the sites-available file (/etc/raddb/sites-available) and edit the file "inner-tunnel". In the authorize section comment out (using a #) the word "files", and uncomment the word "ldap". In the authenticate section again comment out the "files" line and uncomment the ldap section so it looks like this:
Auth-Type LDAP {
    ldap
}
Now we can edit the "default" file in the same folder, and make the exact same changes as the inner-tunnel file above.

Once this is done we can start defining our clients, this is in the file /etc/raddb/clients.conf and add your ASA in:
client 192.168.2.253 {
        secret = test123
        shortname = testasa
        nastype = cisco
}
With the secret being the shared secret you are going to use on your ASA.

In order to get both SSH and ASDM working as we need them to we need to uncomment one line in /usr/share/freeradius/dictionary, look for the following:
#
#        The Cisco VPN300 dictionary is the same as the altiga one.
#        You shouldn't use both at the same time.
#
#$INCLUDE dictionary.cisco.vpn3000
Just uncomment the $INCLUDE dictionary.cisco.vpn3000, and save the file.

Before we set up our ASA we are going to set up our group access in Radius, and to do that we go back into the default file. In the post-auth section I added the following:
if (LDAP-Group == "sec-fw-Administrator") {
        update reply {
                Service-Type = "Administrative-User",
                Cisco-AVPair = "shell:roles=network-admin",
                Cisco-AVPair += "shell:priv-lvl=15",
                CVPN3000-Privilege-Level = 15
                }
}
elsif (LDAP-Group == "sec-fw-readonly") {
        update reply {
                Service-Type = "Administrative-User",
                Cisco-AVPair = "shell:roles=network-operator",
                Cisco-AVPair += "shell:priv-lvl=1",
                CVPN3000-Privilege-Level = 3
                }
}
else {
                reject
}
Here we are specifying that a member of sec-fw-administrator should be an administrative user, with privilege level 15. The network-admin line is ready for when we switch our Nexus to use freeradius (as previously we set our Nexus to use Microsoft NPS as well). If our user is not a member of sec-fw-administrator then we need to see if they are a member of sec-fw-readonly, it they are then they should get into the ASA but only at a maximum of level 3. Finally if they are not a member of either the connection attempt should be rejected.

Finally we can switch our ASA to use freeradius, the config looks like this:
aaa-server FreeRadius protocol radius
aaa-server FreeRadius (Inside) host 192.168.3.121
 key test123
 authentication-port 1812
 accounting-port 1813
aaa authentication ssh console FreeRadius LOCAL
aaa authentication enable console FreeRadius LOCAL
aaa authentication http console FreeRadius LOCAL
aaa accounting enable console FreeRadius
aaa accounting ssh console FreeRadius
aaa authorization exec authentication-server
Now we can test. Firstly by logging in with my account:
login as: sfordham
sfordham@192.168.2.253's password:
Type help or '?' for a list of available commands.
testasa> sh curp
Username : sfordham
Current privilege level : 1
Current Mode/s : P_UNPR
testasa> en
Password: *********
testasa# sh curp
Username : sfordham
Current privilege level : 15
Current Mode/s : P_PRIV
testasa#
And with ASDM:

Next we test with a readonly level account:
login as: testnps
testnps@192.168.2.253's password:
Type help or '?' for a list of available commands.
testasa> sh curp
Username : testnps
Current privilege level : 1
Current Mode/s : P_UNPR
testasa> en
Password: ***********
testasa# sh curp
Username : testnps
Current privilege level : 3
Current Mode/s : P_PRIV
testasa#
And with ASDM:

Lastly with an account that should be rejected:



Finally we have a working solution!

CCIE #49337, author of CCNA and Beyond, BGP for Cisco Networks, MPLS for Cisco Networks, VPNs and NAT for Cisco Networks.

Related Posts

Previous
Next Post »