ADCLI(8)

🌸 ADCLI(8) β€” the adcli appreciation post 🌸

okay bestie, sit down, hydrate, and let me tell you about adcli β€” a command line tool that performs actions on an Active Directory domain. Among other things it can be used to join a computer to a domain. Yes, that kind of tool. The iconic one. πŸŽ€


✨ NAME ✨

adcli β€” Tool for performing actions on an Active Directory domain


πŸ¦‹ SYNOPSIS πŸ¦‹

Like, here's the whole menu, no cap. Every single one of these is a real vibe:

adcli info domain.example.com

adcli join domain.example.com

adcli update

adcli testjoin

adcli create-user [--domain=domain.example.com] user

adcli delete-user [--domain=domain.example.com] user

adcli passwd-user [--domain=domain.example.com] user

adcli create-group [--domain=domain.example.com] user

adcli delete-group [--domain=domain.example.com] user

adcli add-member [--domain=domain.example.com] group user or computer...

adcli remove-member [--domain=domain.example.com] group user...

adcli preset-computer [--domain=domain.example.com] computer...

adcli reset-computer [--domain=domain.example.com] computer

adcli delete-computer [--domain=domain.example.com] computer

adcli show-computer [--domain=domain.example.com] computer

adcli create-msa [--domain=domain.example.com]

πŸ’… GENERAL OVERVIEW πŸ’…

So adcli is a command line tool that can perform actions in an Active Directory domain. Among other things β€” and honestly this is the main character move β€” it can be used to join a computer to a domain. πŸ‘‘

Check out the various sub commands below. And the following global options work all across the board, bestie:

  • -D, --domain=domain β€” the domain to connect to. If you don't specify a domain, no stress, the domain part of the local computer's host name gets used instead. 🫢
  • -R, --domain-realm=REALM β€” the Kerberos realm for the domain. Not specified? Then it just uses the upper cased domain name. Easy.
  • -S, --domain-controller=server β€” connect to one specific domain controller. If you don't pick one, an appropriate domain controller gets automatically discovered. She finds her own way. ✨
  • --use-ldaps β€” connect to the domain controller with LDAPS. By default the LDAP port is used and SASL GSS-SPNEGO or GSSAPI is used for authentication and to establish encryption. This should satisfy all requirements set on the server side, and LDAPS should only be used if the LDAP port is not accessible due to firewalls or other reasons. Like, LDAPS is the special occasion outfit, not the everyday fit. πŸ’€
Please note that the place where CA certificates can be found to validate the AD DC certificates must be configured in the OpenLDAP configuration file, e.g. /etc/openldap/ldap.conf. As an alternative it can be specified with the help of an environment variable, e.g. text $ LDAPTLS_CACERT=/path/to/ad_dc_ca_cert.pem adcli join --use-ldaps -D domain.example.com ... Please see ldap.conf(5) for details. πŸ“–
  • -C β€” use the default Kerberos credential cache to authenticate with the domain.
  • --login-ccache[=ccache_name] β€” use the specified Kerberos credential cache to authenticate with the domain. If no credential cache is specified, the default Kerberos credential cache will be used. Credential caches of type FILE can be given with the path to the file. For other credential cache types, e.g. DIR, KEYRING or KCM, the type must be specified explicitly together with a suitable identifier.
⚠️ Please note that since the ccache_name is optional the = (equal) sign is mandatory. If = is missing the parameter is treated as optionless extra argument. How this is handled depends on the specific sub-command. Don't let the missing = jump you, fr fr. πŸ™ˆ
  • -U, --login-user=User β€” use the specified user account to authenticate with the domain. If not specified, then the name Administrator will be used. (yes, that one. the classic.)
  • --no-password β€” don't show prompts for or read a password from input. Sometimes we simply do not wish to be perceived. πŸ«₯
  • -W, --prompt-password β€” prompt for a password if necessary. This is the default, so it's already doing the most. πŸ’–
  • --stdin-password β€” read a password from stdin input instead of prompting for a password. Piping it in like a boss.
  • -v, --verbose β€” run in verbose mode with debug output. The "tell me everything" era. πŸ”₯

🌈 QUERYING DOMAIN INFORMATION 🌈

adcli info displays discovered information about an Active Directory domain or an Active Directory domain controller. It's giving detective, it's giving receipts. πŸ”

$ adcli info domain.example.com
...

$ adcli info --domain-controller=dc.domain.example.com
...

adcli info will output as much information as it can about the domain. The information is designed to be both machine and human readable β€” bilingual queen. πŸ’… The command will exit with a non-zero exit code if the domain does not exist or cannot be reached. 😭

To show domain info for a specific domain controller use the --domain-controller option to specify which domain controller to query. Be specific, bestie.

Use the --verbose option to show details of how the domain is discovered and queried. πŸ’–

Heads up though: many of the global options, in particular authentication options, are not usable with the adcli info command. She's an independent woman, she doesn't need those. πŸ‘‘

πŸŽ€ JOINING THE LOCAL MACHINE TO A DOMAIN πŸŽ€

Okay so this is the main character move: adcli join creates a computer account in the domain for the local machine, and sets up a keytab for the machine. That's it, that's the whole vibe. It does not configure an authentication service (such as sssd) β€” like, don't come for adcli when your sssd situation is a mess, it literally told you. πŸ’…

Here's what it looks like in the wild:

$ adcli join domain.example.com
Password for Administrator:

In addition to the global options, you can specify the following options to control how this operation is done. Buckle up bestie, there's a lot of them and honestly? They all ate. 🌈

  • -N, --computer-name=computer β€” The short, non-dotted name of the computer account that will be created in the domain. If you don't specify it, then the first portion of the --host-fqdn is used. 🫢
  • -O, --domain-ou=OU=xxx β€” The full distinguished name of the OU in which to create the computer account. If you don't specify it, then the computer account will be created in a default location.
  • -H, --host-fqdn=host β€” Override the local machine's fully qualified domain name. If not specified, the local machine's hostname will be retrieved via gethostname(). And if gethostname() only returns a short name, getaddrinfo() with the AI_CANONNAME hint is called to expand the name to a fully qualified domain name. Look at her working for that FQDN. πŸ’–
  • -K, --host-keytab=/path/to/keytab β€” Specify the path to the host keytab where host credentials will be written after a successful join operation. If not specified, the default location will be used, usually /etc/krb5.keytab. πŸ—οΈ
  • --login-type={computer|user} β€” Specify the type of authentication that will be performed before creating the machine account in the domain. If set to 'computer', then the computer must already have a preset account in the domain. If not specified and none of the other --login-xxx arguments have been specified, then it will try both 'computer' and 'user' authentication. (Overachiever behavior, honestly. ✨)
  • --os-name=name β€” Set the operating system name on the computer account. The default depends on where adcli was built, but is usually something like 'linux-gnu'.
  • --os-service-pack=pack β€” Set the operating system service pack on the computer account. Not set by default.
  • --os-version=version β€” Set the operating system version on the computer account. Not set by default.
  • --description=description β€” Set the description attribute on the computer account. Not set by default. Go on, give your machine a little bio. πŸ“
  • --service-name=service β€” Additional service name for a Kerberos principal to be created on the computer account. This option may be specified multiple times. Yup, stack 'em. πŸ”₯
  • --user-principal=host/name@REALM β€” Set the userPrincipalName field of the computer account to this Kerberos principal. If you omit the value for this option, then a principal will be set in the form of host/host.example.com@REALM.
  • --one-time-password β€” Specify a one time password for a preset computer account. This is equivalent to using --login-type=computer and providing a password as input. ⚑
  • --trusted-for-delegation=yes|no|true|false β€” Set or unset the TRUSTED_FOR_DELEGATION flag in the userAccountControl attribute to allow or not allow that Kerberos tickets can be forwarded to the host.
  • --dont-expire-password=yes|no|true|false β€” Set or unset the DONT_EXPIRE_PASSWORD flag in the userAccountControl attribute to indicate if the machine account password should expire or not. By default adcli will set this flag while joining the domain, which corresponds to the default behavior of Windows clients.
⚠️ Please note that if the password will expire (--dont-expire-password=false), a renewal mechanism has to be enabled on the client to not lose the connectivity to AD if the password expires. Like, do not skip this part, bestie, your connectivity will simply ghost you. 😭
  • --add-service-principal=service/hostname β€” Add a service principal name. In contrast to the --service-name, the hostname part can be specified as well, in case the service should be accessible with a different host name as well. Flexible queen. πŸ‘‘
  • --setattr=name=value β€” Add the LDAP attribute name with the given value to the new LDAP host object. This option can be used multiple times to add multiple different attributes. Multi-value attributes are currently not supported.
πŸ’€ Please note that the account used to join the domain must have the required privileges to add the given attributes. Some attributes might have constraints with respect to syntax and allowed values which must be met as well. And β€” important β€” attributes managed by other adcli options cannot be set with this option. No double-dipping, bestie.
  • --show-details β€” After a successful join, print out information about the join operation. This is output in a format that should be both human and machine readable. She's bilingual, she contains multitudes. πŸ¦‹
  • --show-password β€” After a successful join, print out the computer machine account password. This is output in a format that should be both human and machine readable. πŸ”‘
  • --add-samba-data β€” After a successful join, add the domain SID and the machine account password to the Samba specific databases by calling Samba's net utility.
🌸 Please note that Samba's net requires some settings in smb.conf to create the database entries correctly. Most important here are currently the workgroup, realm and security options, see smb.conf(5) for details.
  • --samba-data-tool=/path/to/net β€” If Samba's net cannot be found at /usr/bin/net, this option can be used to specify an alternative location with the help of an absolute path. (Absolute path only, she's not doing guesses today. πŸ™ˆ)
  • --ldap-passwd β€” Use LDAP add/mod operations to set the machine account password instead of Kerberos. This might help in some situations where Kerberos fails or is unreliable. But please note that 'Change password' or 'Reset password' permissions or similar might be needed to make the LDAP operation work. Additionally there will be no read-only domain controller (RODC) support as there is with Kerberos. Trade-offs, bestie, there are always trade-offs. πŸ’…

If supported on the AD side, the msDS-supportedEncryptionTypes attribute will be set as well. Either the current value or the default list of AD's supported encryption types, filtered by the permitted encryption types of the client's Kerberos configuration, are written. ⭐

And one more little cleanup detail: if the computer object already exists in AD and in the userAccountControl attribute the flag USE_DES_KEY_ONLY is set, the flag will be removed during the join β€” because in current environments using DES for encryption is deprecated since quite some time or already disabled. So long, DES, you will not be missed. πŸ’€βœ¨

🌸 UPDATING THE MACHINE ACCOUNT PASSWORD AND OTHER ATTRIBUTES 🌸

okay so adcli update is the glow-up for your local machine's computer account. It updates the password of the computer account on the domain controller for the local machine, writes the new keys to the keytab, and removes older keys. It keeps the previous key on purpose because AD will need some time to replicate the new key to all DCs, hence the previous key might still be used. bestie, that's not laziness, that's strategy πŸ’…

Service principal names get synced between the keytab and the Active Directory computer object in the sense that principals missing on either side will be added automatically. To remove service principals, you have to use the --remove-service-principal command line option. no shortcuts there ✨

$ adcli update

If you're using a credential cache, other attributes of the computer account can be changed as well β€” as long as the principal has sufficient privileges. highkey useful πŸ‘‘

$ kinit Administrator
$ adcli update --login-ccache=/tmp/krbcc_123

In addition to the global options, you can specify the following options to control how this operation is done.

  • -N, --computer-name=computer β€” the short non-dotted name of the computer account that will be created in the domain. If you don't specify it, it will be retrieved from the keytab entries.
  • -H, --host-fqdn=host β€” the local machine's fully qualified domain name. If you don't specify it, the local machine's hostname will be retrieved from the keytab entries.
  • -K, --host-keytab=/path/to/keytab β€” specify the path to the host keytab where current host credentials are stored and the new ones will be written to. If you don't specify it, the default location will be used, usually /etc/krb5.keytab.
  • --os-name=name β€” set the operating system name on the computer account. Not set by default.
  • --os-service-pack=pack β€” set the operating system service pack on the computer account. Not set by default.
  • --os-version=version β€” set the operating system version on the computer account. Not set by default.
  • --description=description β€” set the description attribute on the computer account. Not set by default.
  • --service-name=service β€” additional service name for a Kerberos principal to be created on the computer account. This option may be specified multiple times.
  • --user-principal=host/name@REALM β€” set the userPrincipalName field of the computer account to this Kerberos principal.
  • --computer-password-lifetime=lifetime β€” only update the password of the computer account if it is older than the lifetime given in days. By default the password is updated if it is older than 30 days.
  • --trusted-for-delegation=yes|no|true|false β€” set or unset the TRUSTED_FOR_DELEGATION flag in the userAccountControl attribute to allow or not allow that Kerberos tickets can be forwarded to the host.
  • --dont-expire-password=yes|no|true|false β€” set or unset the DONT_EXPIRE_PASSWORD flag in the userAccountControl attribute to indicate if the machine account password should expire or not. By default adcli will set this flag while joining the domain, which corresponds to the default behavior of Windows clients.
Please note that if the password will expire (--dont-expire-password=false) a renewal mechanism has to be enabled on the client to not lose connectivity to AD if the password expires. like, actually enable it, bestie 😭
  • --account-disable=yes|no|true|false β€” set or unset the ACCOUNTDISABLE flag in the userAccountControl attribute to disable or enable the computer account.
  • --add-service-principal=service/hostname β€” add a service principal name. In contrast to the --service-name option, the hostname part can be specified as well in case the service should be accessible with a different host name as well.
  • --remove-service-principal=service/hostname β€” remove a service principal name from the keytab and the AD host object.
  • --setattr=name=value β€” add the LDAP attribute name with the given value to the LDAP host object. This option can be used multiple times to add multiple different attributes. Multi-value attributes are currently not supported.
Please note that the account used to update the host object must have the required privileges to modify the given attributes. Some attributes might have constraints with respect to syntax and allowed values which must be met as well. Attributes managed by other adcli options cannot be set with this option. 🫢
  • --delattr=name β€” remove the LDAP attribute name from the LDAP host object. This option can be used multiple times to remove multiple different attributes.
Please note that the account used to update the host object must have the required privileges to delete the given attributes. Attributes managed by other adcli options cannot be removed. periodt 🫢
  • --show-details β€” after a successful join, print out information about the join operation. This is output in a format that should be both human and machine readable.
  • --add-samba-data β€” after a successful join, add the domain SID and the machine account password to the Samba specific databases by calling Samba's net utility.
Please note that Samba's net requires some settings in smb.conf to create the database entries correctly. Most important here are currently the workgroup, realm and security options, see smb.conf(5) for details. Note that if the machine account password is not older than 30 days, you have to pass --computer-password-lifetime=0 to force the update. yes, force it, bestie πŸ’€
  • --samba-data-tool=/path/to/net β€” if Samba's net cannot be found at /usr/bin/net, this option can be used to specify an alternative location with the help of an absolute path.
  • --ldap-passwd β€” use LDAP add/mod operations to set the machine account password instead of Kerberos. This might help in some situations where Kerberos fails or is unreliable. But please note that 'Change password' or 'Rest password' permissions or similar might be needed to make the LDAP operation work. Additionally there will be no read-only domain controller (RODC) support as there is with Kerberos.

If supported on the AD side, the msDS-supportedEncryptionTypes attribute will be set as well. Either the current value or the default list of AD's supported encryption types filtered by the permitted encryption types of the client's Kerberos configuration are written. cute little encryption sync, no cap πŸ”₯


πŸ§ͺ TESTING IF THE MACHINE ACCOUNT PASSWORD IS VALID πŸ§ͺ

adcli testjoin uses the current credentials in the keytab and tries to authenticate with the machine account to the AD domain. If this works, the machine account password and the join are still valid. If it fails, the machine account password or the whole machine account have to be refreshed with adcli join or adcli update. vibe check for your machine account, literally 🫢

$ adcli testjoin

Only the global options not related to authentication are available. Additionally, you can specify the following options to control how this operation is done.

  • -K, --host-keytab=/path/to/keytab β€” specify the path to the host keytab where current host credentials are stored and the new ones will be written to. If you don't specify it, the default location will be used, usually /etc/krb5.keytab.

πŸŽ€ CREATING A USER πŸŽ€

adcli create-user creates a new user account in the domain. main character creation energy ✨

$ adcli create-user Fry --domain=domain.example.com \
     --display-name="Philip J. Fry" --mail=fry@domain.example.com

In addition to the global options, you can specify the following options to control how the user is created.

  • --display-name="Name" β€” set the displayName attribute of the new created user account.
  • -O, --domain-ou=OU=xxx β€” the full distinguished name of the OU in which to create the user account. If not specified, then the computer account will be created in a default location. that's what the page says, bestie, I'm just the messenger 😭
  • --mail=email@domain.com β€” set the mail attribute of the new created user account. This attribute may be specified multiple times.
  • --unix-home=/home/user β€” set the unixHomeDirectory attribute of the new created user account, which should be an absolute path to the user's home directory.
  • --unix-gid=111 β€” set the gidNumber attribute of the new created user account, which should be the user's numeric primary group id.
  • --unix-shell=/bin/shell β€” set the loginShell attribute of the new created user account, which should be a path to a valid shell.
  • --unix-uid=111 β€” set the uidNumber attribute of the new created user account, which should be the user's numeric primary user id.
  • --nis-domain=nis_domain β€” set the msSFU30NisDomain attribute of the new created user account, which should be the user's NIS domain if the NIS/YP service of Active Directory's Services for Unix (SFU) are used. This is needed to let the 'UNIX attributes' tab of older Active Directory versions show the set UNIX specific attributes. If not specified, adcli will try to determine the NIS domain automatically if needed.

πŸ’€ DELETING A USER πŸ’€

adcli delete-user deletes a user account from the domain. not the fun part, but necessary πŸ’…

$ adcli delete-user Fry --domain=domain.example.com

The various global options can be used.


πŸ” (RE)SETTING THE PASSWORD OF A USER WITH AN ADMINISTRATIVE ACCOUNT πŸ”

adcli passwd-user sets or resets the password of a user account. The administrative account used for this operation must have privileges to set a password. with great power etc etc πŸ‘‘

$ adcli passwd-user Fry --domain=domain.example.com

The various global options can be used.


πŸ‘― CREATING A GROUP πŸ‘―

adcli create-group creates a new group in the domain. group chat but make it AD 🌈

$ adcli create-group Pilots --domain=domain.example.com \
     --description="Group for all pilots"

In addition to the global options, you can specify the following options to control how the group is created.

  • --description="text" β€” set the description attribute of the new created group.
  • -O, --domain-ou=OU=xxx β€” the full distinguished name of the OU in which to create the group. If not specified, then the group will be created in a default location.

πŸ—‘οΈ DELETING A GROUP πŸ—‘οΈ

adcli delete-group deletes a group from the domain.

$ adcli delete-group Pilots --domain=domain.example.com

The various global options can be used.


🫢 ADDING A MEMBER TO A GROUP 🫢

adcli add-member adds one or more users to a group in the domain. The group is specified first, and then the various users or computers to be added. You must use a dollar sign for a computer account (computername$). yes, the $ is part of the name, don't forget it 🫢

$ adcli add-member --domain=domain.example.com Pilots Leela Scruffy
$ adcli add-member --domain=domain.example.com servers srv-smb$

The various global options can be used.

πŸ’… REMOVING A MEMBER FROM A GROUP πŸ’…

okay so adcli remove-member is literally the breakup artist of adcli β€” it removes a user from a group in the domain. the group comes first (main character energy, obviously), and then all the users you wanna yeet out of it. 🫢

$ adcli remove-member --domain=domain.example.com Pilots Scruffy

and yeah, the various global options can be used here too. slay.


✨ PRESET COMPUTER ACCOUNTS ✨

adcli preset-computer is giving ✨preparedness queen✨ β€” it pre-creates one or more computer accounts in the domain for machines to later use when they join the domain. and the way this works is lowkey genius: machines can then join using a one time password, or automatically with no password at all. πŸ”₯

$ adcli preset-computer --domain=domain.example.com \
     host1.example.com host2
Password for Administrator:

vibe check on the names: if the computer names you pass contain dots, they're treated as fully qualified host names. no dots? then they're treated as short computer names. also β€” important β€” the computer accounts must not already exist, so don't come at it with duplicates bestie. πŸ’€

in addition to the global options, you can specify the following options to control how this operation is done:

  • -O, --domain-ou=OU=xxx β€” the full distinguished name of the OU in which to create the computer accounts. if you don't specify it, the computer account gets created in a default location. πŸŽ€
  • --one-time-password β€” specify a one time password to use when presetting the computer accounts. if you don't specify it, then a default password will be used, which allows for later automatic joins. iconic.
  • --os-name=name β€” sets the operating system name on the computer account. the default depends on where adcli was built, but it's usually something like 'linux-gnu'. 🐧
  • --os-service-pack=pack β€” sets the operating system service pack on the computer account. not set by default.
  • --os-version=version β€” sets the operating system version on the computer account. not set by default.
  • --service-name=service β€” an additional service name for a Kerberos principal to be created on the computer account. you can specify this option multiple times. ⭐
  • --user-principal β€” sets the userPrincipalName field of the computer account to this Kerberos principal in the form of host/host.example.com@REALM.

🌸 RESET COMPUTER ACCOUNT 🌸

adcli reset-computer resets a computer account in the domain. and bestie, listen β€” if the appropriate machine is currently joined to the domain, then its membership will be broken. 😭 the account must already exist.

$ adcli reset-computer --domain=domain.example.com host2

dots check again: if the computer names you pass contain dots, they're treated as fully qualified host names, otherwise they're treated as short computer names.

in addition to the global options, you can specify the following options to control how this operation is done:

  • --login-type={computer|user} β€” specify the type of authentication that will be performed before creating the machine account in the domain. if set to 'computer', then the computer must already have a preset account in the domain. if you don't specify it and none of the other --login-xxx arguments have been specified, then it'll try both 'computer' and 'user' authentication. multitasking king. πŸ‘‘

πŸ¦‹ DELETE COMPUTER ACCOUNT πŸ¦‹

adcli delete-computer deletes a computer account in the domain. the account must already exist β€” no creating-and-deleting in one breath, that's not the vibe.

$ adcli delete-computer --domain=domain.example.com host2
Password for Administrator:

if the computer name contains a dot, then it's treated as a fully qualified host name, otherwise it's treated as a short computer name.

and if no computer name is specified? then the host name of the computer adcli is running on is used, as returned by gethostname(). it just knows. ✨

in addition to the global options, you can specify the following option to control how this operation is done:

  • --recursive β€” if a computer object has child objects, this option must be used to delete the computer object and all child objects. if the option isn't used in this case, adcli will print an error message indicating that this option is needed. so like, it'll tell you. loudly. πŸ’€

πŸ’– SHOW COMPUTER ACCOUNT ATTRIBUTES πŸ’–

adcli show-computer shows the computer account attributes stored in AD. the account must already exist.

$ adcli show-computer --domain=domain.example.com host2
Password for Administrator:

if the computer name contains a dot, then it's treated as a fully qualified host name, otherwise it's treated as a short computer name.

if no computer name is specified, then the host name of the computer adcli is running on is used, as returned by gethostname().

the various global options can be used. periodt.


πŸ‘‘ CREATE A MANAGED SERVICE ACCOUNT πŸ‘‘

okay this one is the plot twist of the whole page β€” adcli create-msa creates a managed service account (MSA) in the given Active Directory domain. ngl it's genuinely useful if a computer should not fully join the Active Directory domain but LDAP access is needed. πŸŽ€

the typical use case? the computer is already joined to an Active Directory domain and needs access to another Active Directory domain in the same or a trusted forest where the host credentials from the joined Active Directory domain are not valid β€” like when there's only a one-way trust. iykyk. πŸ”₯

$ adcli create-msa --domain=domain.example.com
Password for Administrator:

here's the lore: the managed service account, as maintained by adcli, cannot have additional service principal names (SPNs) associated with it. an SPN is defined within the context of a Kerberos service which is tied to a machine account in Active Directory. since a machine can be joined to a single Active Directory domain, a managed service account in a different Active Directory domain will not have the SPNs that otherwise are part of another Active Directory domain's machine. that's just how it is, bestie. πŸ™ˆ

and since it's expected that a client will most probably join the Active Directory domain matching its DNS domain, the managed service account will be needed for a different Active Directory domain β€” and as a result the Active Directory domain name is a mandatory option. 🚨 if called with no other options, adcli create-msa will use the short hostname with an additional random suffix as the computer name, to avoid name collisions. girlboss move honestly.

now the character limits, because AD is petty like that: the LDAP attribute sAMAccountName has a limit of 20 characters. however, the machine account's NetBIOS name must be at most 16 characters long, including a trailing '$' sign. since it's not expected that the managed service accounts created by adcli will be used on the NetBIOS level, the remaining 4 characters can be used to add uniqueness. πŸ’…

so: managed service account names will have a suffix of 3 random characters from number and upper- and lowercase ASCII ranges appended to the chosen short host name, using '!' as a separator. for a host with the shortname 'myhost', a managed service account will have a common name (CN attribute) 'myhost!A2c' and a NetBIOS name (sAMAccountName attribute) will be 'myhost!A2c$'. a corresponding Kerberos principal in the Active Directory domain where the managed service account was created would be 'myhost!A2c$@DOMAIN.EXAMPLE.COM'. literally aesthetic. ✨

a keytab for the managed service account is stored into a file specified with the -K option. if it's not specified, the file is named after the default keytab file, with the lowercase Active Directory domain of the managed service account as a suffix. on most systems that would be /etc/krb5.keytab with a suffix of 'domain.example.com', e.g. /etc/krb5.keytab.domain.example.com.

adcli create-msa can be called multiple times to reset the password of the managed service account. 🫢 to identify the right account with the random component in the name, the corresponding principal is read from the keytab. and if the keytab got deleted? adcli will try to identify an existing managed service account with the help of the fully-qualified name β€” and if that fails, a new managed service account will be created. adaptive queen.

the managed service account password can be updated with 🧚

$ adcli update --domain=domain.example.com --host-keytab=/etc/krb5.keytab.domain.example.com

and the managed service account can be deleted with 🌈

$ adcli delete-computer --domain=domain.example.com 'myhost!A2c'

in addition to the global options, you can specify the following options to control how this operation is done:

  • -N, --computer-name=computer β€” the short non-dotted name of the managed service account that will be created in the Active Directory domain. the long option name --computer-name is kept to underline the similarity with the same option of the other sub-commands. if not specified, then the first portion of the --host-fqdn or its default is used with a random suffix. πŸŽ€
  • -O, --domain-ou=OU=xxx β€” the full distinguished name of the OU in which to create the managed service account. if not specified, then the managed service account will be created in a default location.
  • -H, --host-fqdn=host β€” override the local machine's fully qualified DNS domain name. if not specified, the local machine's hostname will be retrieved via gethostname(). if gethostname() only returns a short name, getaddrinfo() with the AI_CANONNAME hint is called to expand the name to a fully qualified DNS domain name. ⭐
  • -K, --host-keytab=/path/to/keytab β€” specify the path to the host keytab where credentials of the managed service account will be written after a successful creation. if not specified, the default location will be used, usually /etc/krb5.keytab with the lower-cased Active Directory domain name added as a suffix e.g. /etc/krb5.keytab.domain.example.com.
  • --show-details β€” after a successful creation, print out information about the created object. this is output in a format that should be both human and machine readable. πŸ‘€
  • --show-password β€” after a successful creation, print out the managed service account password. this is output in a format that should be both human and machine readable. πŸ”₯

πŸ’… DELEGATED PERMISSIONS πŸ’…

okay so in AD it’s super common to not join a machine using an account from the Domain Administrators group. Instead, people use a dedicated account that only has permissions to join a machine to one or more OUs in the Active Directory tree. Giving those needed permissions to a single account or a group in Active Directory is literally called Delegation. There’s a classic example in the Delegation section of the blog post Who can add workstation to the domain[1]. 🫢

When you use an account with delegated permissions with adcli, basically the same applies. But I’m gonna zoom in on a few aspects here so the AD concepts are clearer and permission issues during the join are easier to debug. Please note: the following is not specific to adcli β€” it applies to all applications that want to modify certain properties or objects in Active Directory with an account that has limited permissions. ✨

First, like the blog post says, having the Create computer object permission is enough to join a computer to a domain. But that only works as expected if the computer object does not already exist in Active Directory before the join. Why? Because only when a new object is created does Active Directory skip additional permission checks on the attributes of that new computer object. That means the delegated user can add any kind of attribute with any value to a new computer object, as long as they meet general constraints like: the attribute must be defined in the schema and allowed in an objectclass of the object, the value must match the syntax defined in the schema, and the sAMAccountName must be unique in the domain. πŸ‘‘

If you want to use the delegated-permission account to remove computer objects in Active Directory (adcli delete-computer), then yeah, make sure that account has the Delete computer object permission. obviously. πŸ’…

If the computer object already exists, the Create computer object permission does not apply anymore, because now an existing object must be modified. Now you need permissions on the individual attributes, e.g. Read and write Account Restrictions or Reset Password. For some attributes Active Directory has two types of permissions: the plain Read and Write permissions and the Validated Write permissions. For the latter case there are two specific permissions relevant for adcli, namely:

  • Validated write to DNS host name
  • Validated write to service principal name

Details about how values get validated live in the Validated Writes section of [MS-ADTS], especially dNSHostName[2] and servicePrincipalName[3]. To cut it short for Validated write to DNS host name: the domain part of the fully-qualified hostname must either match the domain name of the domain you want to join to, or must be listed in the msDS-AllowedDNSSuffixes attribute. And for Validated write to service principal name: the hostname part of the service principal name must match the name stored in dNSHostName or some other attributes which are not handled by adcli. This also means dNSHostName cannot be empty or only contain a short name if the service principal name should contain a fully-qualified name. πŸ¦‹

To summarize: if you only have validated write permissions, make sure the domain part of the hostname matches the domain you want to join, or use --host-fqdn with a matching name. periodt.

The plain read write permissions do not run additional validations, but the attribute values still have to agree with the general constraints mentioned above. If the computer object already exists, adcli might need the following permissions, which are also needed by Windows clients to modify existing attributes:

  • Reset Password
  • Read and write Account Restrictions
  • Read and (validated) write to DNS host name
  • Read and (validated) write to service principal name

additionally adcli needs:

  • Read and write msDS-supportedEncryptionTypes

This one is added for security reasons: it avoids Active Directory storing Kerberos keys with (potentially weaker) encryption types than the client supports, since Active Directory is often configured to still support older (weaker) encryption types for compatibility reasons. πŸ”₯

All other attributes are only set or modified on demand, i.e. adcli must be called with an option that would set or modify the given attribute. In the following, the attributes adcli can modify together with the required permissions are listed:

  • userPrincipalName
    • Read/Write userPrincipal Name
  • msDS-supportedEncryptionTypes
    • Read/Write msDS-SupportedEncryptionTypes
  • dNSHostName
    • Read/Write dNSHostName
    • Read and write DNS host name attributes
    • Validated write to DNS host name
  • servicePrincipalName
    • Read/Write servicePrincipalName
    • Validated write to service principal name
  • operatingSystem
    • Read/Write Operating System
  • operatingSystemVersion
    • Read/Write Operating System Version
  • operatingSystemServicePack
    • Read/Write operatingSystemServicePack
  • userAccountControl
    • Read/Write userAccountControl
  • description
    • Read/Write Description

For managing users and groups (adcli create-user, adcli delete-user, adcli create-group, adcli delete-group) the same idea applies, just for different types of objects, i.e. users and groups. Since adcli currently only supports the creation and removal of user and group objects, having the Create/Delete User objects and Create/Delete Group objects permissions is sufficient. πŸ’–

If you also want to manage group members (adcli add-member, adcli remove-member), then Read/Write Members permissions are needed as well. slay.

Depending on the version of Active Directory, the Delegation of Control Wizard might offer some shortcuts for common tasks like e.g.:

  • Create, delete and manage user accounts
  • Create, delete and manage groups
  • Modify the membership of a group

The first 2 shortcuts will provide full access to user and group objects, which, as explained above, is more than is currently needed. After using those shortcuts it’s a good idea to verify in the Security tab in the Properties of the related Active Directory container that the assigned permissions meet your expectations. πŸ‘‘


πŸ› BUGS πŸ›

Please send bug reports to either the distribution bug tracker or the upstream bug tracker at

https://bugs.freedesktop.org/enter_bug.cgi?product=realmd&component=adcli

πŸ‘€ SEE ALSO πŸ‘€

realmd(8), net(8), sssd(8)

Further details available in the realmd online documentation at

http://www.freedesktop.org/software/realmd/

πŸŽ€ NOTES πŸŽ€

  1. Who can add workstation to the domain https://docs.microsoft.com/en-us/archive/blogs/dubaisec/who-can-add-workstation-to-the-domain
  2. dNSHostName https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/5c578b15-d619-408d-ba17-380714b89fd1
  3. servicePrincipalName https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/28ca4eca-0e0b-4666-9175-a37ccb8edada

okay that’s the whole page, bestie πŸ’–. Source/version: realmd; page marker: ADCLI(8); date: your local footer has the date stamp doing its little timestamp thing, and we are obsessed πŸŽ€βœ¨

πŸ“¦ where this page comes from