Historically, sudo rights were governed by the contents of files from
/etc/sudoers.d and
visudo , and authorization by keys was done using
~ / .ssh / authorized_keys . However, with the growth of infrastructure, there is a desire to manage these rights centrally. To date, there may be several solutions:
- Configuration Management System - Chef , Puppet , Ansible , Salt
- Active Directory + sssd
- Various perversions in the form of scripts and manual file editing
In my subjective opinion, the best option of centralized management is still a bunch of
Active Directory +
sssd . The advantages of this approach are:
- Indeed a single centralized user directory.
- Distributing sudo rights is as simple as adding a user to a specific security group.
- In the case of various Linux systems, it is necessary to introduce additional checks on the definition of the OS when using configuration systems.
Today’s suite will be dedicated specifically to
Active Directory +
sssd for managing
sudo rights and storing
ssh keys in a single repository.
So, the hall froze in tense silence, the conductor raised his wand, the orchestra prepared.
Go.
Given:
')
- Active Directory domain testopf.local on Windows Server 2012 R2.
- Linux host running Centos 7
- Configured authorization using sssd
Both solutions make changes to the
Active Directory schema , so we check everything on the test environment and only then make changes to the working infrastructure. I want to note - all changes are point and, in fact, add only the necessary attributes and classes.
Step 1: Manage sudo roles through Active Directory .
To extend the
Active Directory schema, you need to download the latest release of
sudo - 1.8.27 today. Unpack, copy the file
schema.ActiveDirectory from the ./doc directory to the domain controller. From the command line with administrator rights from the directory where you copied the file, run:
ldifde -i -f schema.ActiveDirectory -c dc=X dc=testopf,dc=local
(Do not forget to substitute your values)
Open
adsiedit.msc and connect to the default context:
At the root of the domain we create the
sudoers division. (The bourgeois stubbornly asserts that it is in this subdivision that the
sssd daemon searches for
sudoRole objects. However, after turning on detailed debugging and studying logs, it was revealed that the search is performed across the entire directory tree.)
Create in the division the first object belonging to the class
sudoRole . The name can be chosen absolutely arbitrarily, since it serves exclusively for easy identification.
Among the possible attributes available from the schema extension are the following:
- sudoCommand - determines which commands are allowed to be executed on the host.
- sudoHost - defines for which hosts this role applies. It can be set as ALL , or for a single host by name. It is also possible to use a mask.
- sudoUser - specify which users are allowed to run sudo .
In case of specifying a security group, at the beginning of the name add the “%” sign. If there are spaces in the group name, there’s nothing to worry about. Judging by the logs, the sssd mechanism takes over the task of screening spaces.
Figure 1. The sudoRole objects in the sudoers subdivision in the root of the directory
Figure 2. Membership in security groups specified in sudoRole objects.The following setup is done on the Linux side.
In the
/etc/nsswitch.conf file, add the line to the end of the file:
sudoers: files sss
In the
/etc/sssd/sssd.conf file in the
[sssd] section, add
sudo to the services
cat /etc/sssd/sssd.conf | grep services services = nss, pam, sudo
After all operations, you need to clear the sssd daemon cache. Automatic updates are performed every 6 hours, but why should we wait so much when we want to now.
sss_cache -E
It often happens that clearing the cache does not help. Then we stop the service, clean the base, start the service.
service sssd stop rm -rf /var/lib/sss/db/* service sssd start
Connect under the first user and check what is available to him from under sudo:
su user1 [user1@testsshad log]$ id uid=1109801141(user1) gid=1109800513(domain users) groups=1109800513(domain users),1109801132(admins_) [user1@testsshad log]$ sudo -l [sudo] password for user1: Matching Defaults entries for user1 on testsshad: !visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY", secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin User user1 may run the following commands on testsshad: (root) /usr/bin/ls, /usr/bin/cat
Do the same with our second user:
su user2 [user2@testsshad log]$ id uid=1109801142(user2) gid=1109800513(domain users) groups=1109800513(domain users),1109801138(sudo_root) [user2@testsshad log]$ sudo -l Matching Defaults entries for user2 on testsshad: !visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY", secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin User user2 may run the following commands on testsshad: (root) ALL
This approach allows you to centrally define sudo roles for different groups of users.
Storing and using ssh keys in Active Directory
With a small extension of the scheme, it is possible to store ssh keys in the attributes of an Active Directory user and use them when authorizing on Linux hosts.
Authentication via sssd must be configured.
Add the desired attribute using the PowerShell script.
AddsshPublicKeyAttribute.ps1Function New-AttributeID {
$ Prefix = "1.2.840.113556.1.8000.2554"
$ GUID = [System.Guid] :: NewGuid (). ToString ()
$ Parts = @ ()
$ Parts + = [UInt64] :: Parse ($ guid.SubString (0,4), "AllowHexSpecifier")
$ Parts + = [UInt64] :: Parse ($ guid.SubString (4,4), "AllowHexSpecifier")
$ Parts + = [UInt64] :: Parse ($ guid.SubString (9,4), "AllowHexSpecifier")
$ Parts + = [UInt64] :: Parse ($ guid.SubString (14,4), "AllowHexSpecifier")
$ Parts + = [UInt64] :: Parse ($ guid.SubString (19,4), "AllowHexSpecifier")
$ Parts + = [UInt64] :: Parse ($ guid.SubString (24,6), "AllowHexSpecifier")
$ Parts + = [UInt64] :: Parse ($ guid.SubString (30,6), "AllowHexSpecifier")
$ oid = [String] :: Format ("{0}. {1}. {2}. {3}. {4}. {5}. {6}. {7}", $ prefix, $ Parts [ 0]
$ Parts [1], $ Parts [2], $ Parts [3], $ Parts [4], $ Parts [5], $ Parts [6])
$ oid
}
$ schemaPath = (Get-ADRootDSE) .schemaNamingContext
$ oid = New-AttributeID
$ attributes = @ {
lDAPDisplayName = 'sshPublicKey';
attributeId = $ oid;
oMSyntax = 22;
attributeSyntax = "2.5.5.5";
isSingleValued = $ true;
adminDescription = 'User Public key for SSH login';
}
New-ADObject -Name sshPublicKey -Type attributeSchema -Path $ schemapath -OtherAttributes $ attributes
$ userSchema = get-adobject -SearchBase $ schemapath -Filter 'name -eq "user"'
$ userSchema | Set-ADObject -Add @ {mayContain = 'sshPublicKey'}
After adding the attribute, you need to restart Active Directory Domain Services.
Go to the users of Active Directory. In any way convenient for you, we generate a pair of keys for ssh connection.
Start PuttyGen, click the “Generate” button and frantically move the mouse within the empty area.
Upon completion of the process, we can save the public and private keys, pour the public key into the Active Directory user attribute and enjoy the process. However, the public key must be used from the "
Public key for pasting into OpenSSH authorized_keys file: " window.

Add the key to the user attribute.
Option 1 - GUI:

Option 2 - PowerShell:
get-aduser user1 | set-aduser -add @{sshPublicKey = 'AAAAB...XAVnX9ZRJJ0p/Q=='}
So, we have at the moment: a user with the sshPublicKey attribute filled in, a Putty client configured for key authorization. One small moment remains, how can we force the sshd daemon to pull out the public key we need from the user's attributes. A small script successfully found on the open spaces of the bourgeois Internet successfully copes with this.
cat /usr/local/bin/fetchSSHKeysFromLDAP
We put on it the rights 0500 for root.
chmod 0500 /usr/local/bin/fetchSSHKeysFromLDAP
In this example, for the bind to the directory, the administrator account is used. In combat, there should be a separate account with a minimum set of rights.
I personally was very embarrassed by the moment of the password in its pure form in the script, despite the rights granted.
Solution option:
Final chord in today's suite edit sshd_config
cat /etc/ssh/sshd_config | egrep -v -E "#|^$" | grep -E "AuthorizedKeysCommand|PubkeyAuthe" PubkeyAuthentication yes AuthorizedKeysCommand /usr/local/bin/fetchSSHKeysFromLDAP AuthorizedKeysCommandUser root
As a result, we get the following sequence when configured key authorization in the ssh client:
- The user connects to the server, indicating your username.
- The sshd daemon through the script pulls the value of the public key from the user attribute in Active Directory and authorizes the keys.
- The sssd daemon performs further user authentication based on group membership. Attention! If it is not configured, then any user of the domain will have access to the host.
- When attempting to sudo, the sssd daemon searches the Active Directory directory for roles. If roles are present, the attributes and membership of the user in the group are checked (if sudoRoles is configured to use user groups)
Total
Thus, keys are stored in Active Directory user attributes, sudo permissions are similarly, access to Linux hosts by domain accounts is done by checking membership in an Active Directory group.
The final wave of the conductor's wand - and the hall freezes in reverent silence.
Resources used when writing: