Git Product home page Git Product logo

join-domain-formula's Introduction

Travis Build Status AppVeyor Build Status

join-domain-formula

This project uses a SaltStack formula to automate the joining of a Windows or Linux system to an Active Directory (or compatible) domain.

This formula has been tested against Windows Server 2012/2016 and Enterprise Linux 6/7 derivatives (Red Hat, CentOS, Scientific Linux, etc.)

This formula uses data externalized via the SaltStack "Pillar" feature. See the sections below for the data required to be present within the supporting pillar.

join-domain windows

join-domain:
  lookup:
    # Required Settings
    dns_name:
    netbios_name:
    username:

    # Mutually Exclusive Required Settings
    encrypted_password:
    key:
    # or
    password:

    # Optional Settings
    oupath:
    admin_users:
    admin_groups:
    ec2config:
    register_primary_connection_address:
    use_suffix_when_registering:
    tries:

Generating key and encrypted_password for Windows

For Windows systems, to generate the key and the encrypted_password pillar parameters, use the code snippet below:

$String = 'Super secure password'
$StringBytes = [System.Text.UnicodeEncoding]::Unicode.GetBytes($String)
$AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
$AesObject.IV = New-Object Byte[]($AesObject.IV.Length)
$AesObject.GenerateKey()
$KeyBase64 = [System.Convert]::ToBase64String($AesObject.Key)
$EncryptedStringBytes = ($AesObject.CreateEncryptor()).TransformFinalBlock($StringBytes, 0, $StringBytes.Length)
$EncryptedStringBase64 = [System.Convert]::ToBase64String($EncryptedStringBytes)
# Save KeyBase64 in pillar as `key`
"key = $KeyBase64"
# Save EncryptedStringBase64 in pillar as `encrypted_password`
"encrypted_password = $EncryptedStringBase64"

After generating the encrypted password, verify its reversibility by using the code snippet below:

$AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
$AesObject.IV = New-Object Byte[]($AesObject.IV.Length)
$AesObject.Key = [System.Convert]::FromBase64String($KeyBase64)
$EncryptedStringBytes = [System.Convert]::FromBase64String($EncryptedStringBase64)
$UnencryptedString = [System.Text.UnicodeEncoding]::Unicode.GetString(($AesObject.CreateDecryptor()).TransformFinalBlock($EncryptedStringBytes, 0, $EncryptedStringBytes.Length))
"unencrypted_password = $UnencryptedString"

Output of verification should display:

unecrypted_password = Super secure password

Permissions required to join AD Domain

The following are the permissions required for the service account used to join computer clients to the AD domain:

Permission Applies to
Create/delete computer objects This object and all descendant objects
Validated write to DNS hostname Descendant Computer objects
Validated write to service principal name Descendant Computer objects
Write Description Descendant Computer objects
Write msDS-SupportedEncryptionTypes Descendant Computer objects
Write operating system Descendant Computer objects
Write operating system version Descendant Computer objects
Write operating system service pack Descendant Computer objects
Write operating system hot fix Descendant Computer objects
Write public information Descendant Computer objects
Write servicePrincipalName Descendant Computer objects
Read/Write account restrictions Descendant Computer objects
Read all properties Descendant Computer objects

join-domain:linux

The following parameters are used to join a Linux client to Active Directory. See the pillar.example file for pillar-data structuring.

Information used to join host to target AD domain

Set of parameters used for joining a AD-client to its domain:

  • dns_name: The fully-qualified DNS name for the AD domain (e.g., 'aws.lab')

  • ad_site_name: (OPTIONAL) The logical name of an Active Directory Sites and Services site to query for domain-controllers. This is used primarily for the 'openldap-client' connector-option

  • netbios_name: The "short" or NETBIOS name for the AD domain (e.g., 'AWSLAB')

  • username: The account name used to perform automated joins of clients to the AD domain (e.g., 'svc_domjoin_aws'). It is recommended to create a service account that has the bare-minimum permissions necessary to (re)join a client to an AD domain.

  • oupath: (OPTIONAL) where in the AD-hierarchy to create the computer account. Leave blank if joining to the default OU or provide the "/"-delimited path to the OU the computer account will be housed within.

  • encrypted_password: This is an encrypted representation of the join_svc_acct service account's password. Use openssl's aes-256-cbc encryption option to create the encrypted-string.

  • key: The string passed to openssl to encrypt/decrypt the join_svc_acct service account's password.

Information used configure domain-joined client's behvior

  • admin_users: (OPTIONAL) List of users to add to the sudoers system
  • admin_groups: (OPTIONAL) List of groups to add to the sudoers system
  • login_users: (OPTIONAL) List of users to add to SSH daemon's AllowUsers list. Note: all admin_users are automatically included in this list.
  • login_groups: (OPTIONAL) List of groups to add to SSH daemon's AllowGroups list. Note: (OPTIONAL)all admin_groups are automatically included in this list.
  • trusted_domains: (OPTIONAL) List of domains (within a multi-domin forest) to trust

Tool used for joining client to AD domain

There are a number of third-party and native options available for joining Linux clients to AD domains. This parameter is used to tell the formula which client-behavior should be used. Expected valid values will be 'centrify', 'pbis', 'quest', 'sssd' and 'winbind'. As of this version of the formula, 'pbis' and 'sssd' are supported (though use of 'pbis' is now HIGHLY discouraged due to its discontinuation in late 2019).

  • ad_connector: (e.g., 'sssd')

Settings for the URI path-elements to the PBIS installer

These two values are used to determine where to locate the AD-client's installer software. HTTP is the expected (read "tested") download method. Other download methods may also work (but have not been tested).

  • connector_rpms: Top-level search-key for PBIS-related elements. Remaining keys in this block are sub-keys of this key.
  • pbis-open: URL of the pbis-open RPM
  • pbis-open-devel: URL of the pbis-open-devel RPM (rarely used)
  • pbis-open-gui: URL of the pbis-open-gui RPM (rarely used)
  • pbis-open-legacy: URL of the pbis-open-legacy RPM (infrequently used)
  • pbis-open-upgrade: URL of the pbis-open-upgrade RPM

Directories where (the PBIS) AD-client utilities are installed to the system

List of directories associated with the chosen ad_connector software/method.

  • install_bin_dir: Primary installation-directory for the connector-software (e.g., /opt/pbis)

  • install_var_dir: Primary directory for var-style connector-software files (e.g. /var/lib/pbis)

  • install_db_dir: Primary directory hosting connector-software's cache-databases (e.g., /var/lib/pbis/db)

SSSD-specific pillar settings

SSSD configuration parameters for domain-specific .conf files under the /etc/sssd/conf.d/ directory can be provided using the following pillar dictionary parameter:

  • sssd_conf_parameters:
sssd_conf_parameters:
  <key1>: '<value1>'
  ...
  <keyN>: '<valueN>'

Any parameter supported by sssd may be used within sssd_conf_parameters to customize the operation of sssd.

List of RPMs to look for

This is a list of RPMs associated with the AD client. For some client-types (PBIS is known to require this), the formula will evaluate the presence/version of these RPMs to help determine whether the requested install should be performed as a new install or an upgrade (where possible).

  • connectorRpms:

    • RPM1
    • RPM2
    • ...
    • RPMn

List of critical files to look for

This is a list of critical files - typically configuration files - that the formula will look for to help determine whether the requested install should be performed as a new install or an upgrade (where possible). This is only known to be required for the PBIS integration.

  • checkFiles:

    • CFG1
    • CFG2
    • ...
    • CFGn

Generating key and encrypted_password for Linux

The Linux portions of the join-domain-formula make use of a reversible, AES 256-bit ECB-encrypted string to store password data with a Salt pillar. To create the reversible, crypted string, you need three things:

  • The openssl tools
  • The password of the domain-join account
  • A semi-random string to use as the lock/unlock key for the encrypted string.

The lock/unlock key can be either manually or automatically generated. A good method for automatically generating the key is to execute something similar to (< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-10};echo ). This might give you an output similar to F_6ln9jV3X

Once the domain-join account's password and the lock/unlock key are available, use openssl's enc functionality to generate the reversible crypt-sting via a method similar to the following.

$ echo 'MyP@ssw*rd5tr1ng' | \
  openssl enc -aes-256-cbc -md sha256 -a -e -salt -pass pass:'F_6ln9jV3X'
U2FsdGVkX19pOx6FMnowkQ9vVGmHPuL5xWFwY5+EnB7Wy4rYze5HDmSZoTitwZDO

After generating the crypt-string, verify its reversibility by doing something similar to the following:

echo 'U2FsdGVkX19pOx6FMnowkQ9vVGmHPuL5xWFwY5+EnB7Wy4rYze5HDmSZoTitwZDO' | \
  openssl enc -aes-256-cbc -md sha256 -a -d -salt -pass pass:'F_6ln9jV3X'
MyP@ssw*rd5tr1ng

After verification, place the crypt-string and its lock/unlock string into the appropriate Pillar fields.

join-domain-formula's People

Contributors

confusdcodr avatar dalerichardson avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar dwc0011 avatar eemperor avatar ferricoxide avatar lorengordon avatar mergify[bot] avatar userhas404d avatar yakdriver avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

join-domain-formula's Issues

Make it easier to specify the name of the OU in which to place the system

Support an ouname option, that specifies the name of the OU in which to place the system. As a DN still needs to be constructed, this will require additional options, possibly basedn and prependdn (or whatever).

For example, if a user were to specify:

ouname="Super Cool App"
basedn="OU=foo,DC=example,DC=com"
prependdn="OU=Computers"

Then the resulting OU path would be:

"OU=Computers,OU=Super Cool App,OU=foo,DC=example,DC=com"

Linux `fix-collisions.sh` Helper-Script Chokes When `dns_name` Is Multi-Value

Quick Fix: Change the assignment of the script's second argument to an array-assignement.

  • Pro: one line of minimally-changed code required
  • Con: Brittle: requires that joined-to domain always be the first value in the dns_name pillar-key

Full Fix: Rewrite the script to handle a multi-value setting of the dns_name Pillar-key:

  • Pro: Arguably the Right Way™ to do it
  • Cons: Significant rewrite; Script doesn't really need to work against all the domains in a multi-value argument, just the joined-to domain. Complexity-cost of full fix may not justifiable (and may introduce new "wrinkles" to deal with)

Linux `join-domain.sh` Helper-Script Chokes When `dns_name` Is Multi-Value

Quick Fix: Change the assignment of the script's second argument to an array-assignement.

  • Pro: one line of minimally-changed code required
  • Con: Brittle: requires that joined-to domain always be the first value in the dns_name pillar-key

Full Fix: Rewrite the script to handle a multi-value setting of the dns_name Pillar-key:

  • Pro: Arguably the Right Way™ to do it
  • Cons: Significant rewrite; Script doesn't really need to work against all the domains in a multi-value argument, just the joined-to domain. Complexity-cost of full fix may not justifiable (and may introduce new "wrinkles" to deal with)

Support ability to remove access from users or groups

It is desired to be able to specify a list of users and a list of groups that should not have remote access to the system. If a specified user or group currently has remote access, the formula should remove them.

Unable to join Windows to domain in different OU with existing computername

Seems like Windows does not attempt to remove the object when a request is triggered to join a different OU. So doesn't matter what perms the join domain svc acct has, the object has to be removed before adding to another OU.

Verified that this is not an issue with Linux. The object is removed and added by the fix collision script, so may need a similar approach for Windows

join.sh: Password hash decryption-method is not FIPS-compatible

CIS/STIG-hardened EL7 host will be FIPS enabled. When running join-domain-formula/join-domain/elx/pbis/files/join.sh in interactive diagnostic mode, script throws the following error in the decrypt operation:

PWCLEAR=$(echo "${PWCRYPT}" | openssl enc -aes-256-ecb -a -d -salt -pass pass:"${PWUNLOCK}")

produces:

140407787075488:error:060800A3:digital envelope routines:EVP_DigestInit_ex:disabled for fips:digest.c:251:
140407787075488:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:604:

Need to find alternate (FIPS-compatible) method for passing join-user's credentials into the Salt-run.

Add error-exit handler for `adtool` in fix-collision.sh

Depending on configuration of target domain, the adtool utility can exit differently than previously-observed.

Need to:

  1. Add an exit handler
  2. Decide whether to continue, any way, on error from adtool

If "continue any way" is selected, this will allow non-colliding hosts to still attempt to execute a join. However, if there's an unresolved collision, a subsequent join-attempt will fail.

Domain-Join fails if OU Is <null> In Pillar

If the Pillar's ou value is undefined, state will vomit. If Pillar's ou value is set but null, the state will run but will fail as SaltStack will change the null-value to None ...which is generally an invalid OU in AD-domains. This causes pbis-join.sh to execute similar to the following:

domainjoin-cli join --ou None --assumeDefaultDomain yes --userDomainPrefix AWSLAB \
   awslab.localdomain joiner_service 'MyJ0!nP4ss'

Need to add logic to pbis-join.sh to ensure that if passed ou-value is None that the join-command ommits the --ou flag.

Bulk Joins Fail

Encountered issue with production ADs where bulk instance create/join/delete/recreate/join operations fail. Appears that there may be issues with speed with which AD receives the object-delete request and fully removing it from directory. Need to add retry logic - possibly with delay/backoff - to work around AD issues

Make var-usage consistent in find-collision.sh

Currently, initializing DC as an empty array (not compatible with set -u in BASH pre-4.4 but not the actual error)

Subsequently, use DC as a standard var rather than an array

After that reference DC as an array, again.

Bad juju overall...

Need to make the typing-consistent so that set -u is happy with DC's usage on line 126.

Add Parsing for Grains-Based Parameter-Passing

Allow grains to override or complement the values passed via Pillar. This will more easily allow framework users to inject their desired sudoers and login-users AD groups into the configuration setup.

Add "from" hostname to fix-hostname.sh output

Running into cases where the change-hostname behavior is being triggered where it might not ought to be. Need to see what hostname is being used that triggers the action (i.e., are other CM actions only setting the persistent-hostname but leaving the active-hostname at the original value).

Extend Stack-Order Fix To Include /etc/pam.d/system-auth

Fix in issue #23 allows PBIS-based logins to succeed. However, because /etc/pam.d/sudo (and others) reference /etc/pam.d/system-auth via include, repetative sudo-calls exposes misordering in system-auth (pam_faillock spuriously increments until lockout occurs).

Add Support for Enabling LdapSignAndSeal for PBIS

"Out of the box" PBIS configuration is not compatible with domains that have LdapSignAndSeal security-setting enabled/forced. Need to add option to enable LdapSignAndSeal as part of formula's PBIS configuration tasks.

Note: Initial testing indicates that enabling LdapSignAndSeal has no adverse impact using PBIS with domains that don't force its use. Adding the config-item could be done either as a new deployment-default or as a conditional setting (i.e., "use a Pillar toggle").

Update Project-Readme

Need to update the project README's join-domain: linux section. The enumerated keys are no longer 100% correct and the currently-valid keys could use further elaboration.

While there, ensure elaboration on use of the dns_name key in a multi-trust AD forest.

@moskey71 / @Vandalay1125
Opened per today's domain-trust issue

PBIS: `domain-join` Utility Creates Wrong Stack-Order When pam_faillock Present

The pbis.sls leverages the PBIS domainjoin-cli utility to do the heavy-lifting surrounding joining the client to the domain. However, the domainjoin-cli utility (through at least PBIS 8.3.0) defaults to inserting pam_lsass modules late in the /etc/pam.d/password-auth stack. When the pam_faillock modules are present ahead of the pam_lsass modules and a PBIS user attempts to perform password-based authentication, the pam_faillock modules abort the PAM-call before the pam_lsass modules may be referenced. This results in PBIS users only being able to do non-PAM authentications (SSH key, GSSAPI tokens, etc.)

Need to better handle OUs With Spaces In Them

Need to update join-domain-formula/join-domain/elx/pbis/files/join.sh script's local JOINSTAT declaration (in the DomainJoin function) to better handle spaces in OUs.

Need to either better-encapsulate the passed OU-path or need to properly escape any spaces that are present.

Add Support for using OpenLDAP-Clients (ELx)

The OpenLDAP-Clients utilities provide functionalities not present in the native (SSSD) and third-party (PBIS, et. al.) utilities. The ELx join-domain-formula capabilities could be enhanced by making those utilities available (and wrapping key elements in Salt states).

Exception on Windows 2016

It seems the Powershell version in Windows 2016 does not particularly like passing $null as a value to a function...?

watchmaker.exceptions.WatchmakerException: Salt state execution failed:
    set dns search suffix:
        __id__: set dns search suffix
        __run_num__: 81
        changes:
            pid: 492
            retcode: 1
            stderr: "C:\\Users\\Administrator\\AppData\\Local\\Temp\\tmpwi66m_.ps1\
                \ : Cannot validate argument on parameter \r\n'Ec2ConfigSetDnsSuffixList'.\
                \ The argument \"$null\" does not belong to the set \"True,False,\"\
                \ specified by the \r\nValidateSet attribute. Supply an argument that\
                \ is in the set and then try the command again.\r\n    + CategoryInfo\
                \          : InvalidData: (:) [tmpwi66m_.ps1], ParentContainsErrorRecordException\r\
                \n    + FullyQualifiedErrorId : ParameterArgumentValidationError,tmpwi66m_.ps1"
            stdout: ''
        comment: Command 'salt://join-domain/windows/files/Set-DnsSearchSuffix.ps1'
            run
        duration: 1163.0
        name: salt://join-domain/windows/files/Set-DnsSearchSuffix.ps1
        result: false
        start_time: '21:08:01.690000'

Add salt formula syntax validation to Travis CI tests

Prevent Hostname Length Problems

NetBIOS hostname char-limit is 15. Some DHCP-assigned hostnames may exceed this limit - resulting in LDAP_CONSTRAINT_VIOLATION errors. Need to include a method for reliably and uniquely compressing hostnames when a limit-violation is encountered

Joins Report Spurious Failure

There may be an overarching issue with the primary target domain associated with #58. It appears that - with greater frequency - the join operation actually succeeds, but that Saltstack thinks that it failed. This causes the client-config tasks to not run. End result, while things like getent, id, etc. work, PBIS is only partially configured.

Possible that changing the client-config tasks to happen before the join attempt will paper over this issue - may even cause the join-attempt to not report the spurious failure.

Notifying @lorengordon due to potential tie-back to #58

Add Deletion-Validation to LDAP-based Delete-method

Original genesis for the adtool-based was to account for sync-delays in large AD domains.

When using the standard domainjoin method to join a new host to a domain in which there already existed an object of the same name, the operation would sometimes fail despite permissions granted to the join service/account. The domainjoin tool attempts to self-resolve collisions. However, it c/would run into issues where it would talk to one DC for the object-removal and a different DC for object-(re)creation: if the inter-DC sync-delay was longer than the interval between the object-removal action and the object-(re)creation action, the join would fail.

Need to ensure that the LDAP-based removal method does a verification against a couple DCs to make sure the deletion-sync has occurred before handing off to the next state.

Linux/PBIS: Add option to upgrade client-agent version

For lifecycle usage, need to add the capability of upgrading the Linux AD client software's installed version. PBIS will, by default, do an upgrade-in-place if the installer is simply invoked with pbis-open-<VERSION>.linux.<ARCH>.rpm.sh -- --dont-join --legacy install

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.