how do I join the domain in a kickstart file?
Take a look here - http://www.virtuallyghetto.com/2011/02/automating-active-directory-domain-join.html
Remember this is unsupported by VMware, else you can use the vCLI and/or PowerCLI to do so remotely
i put this under %firstboot but getting errors saying
urllib2.HTTPError: HTTP Error 401: Unauthorized
As the post mentions, leave the "password" variable empty, before the final init scripts run, ESXi host has no password. Give that a shot
i removed the root password but in my kickstart file
I have rootpw --iscrypted
is this a problem?
I am still getting an error
urllibz.HTTPerror: Http Error 403: Forbidden: Posssible Cross-Site Request Forgery
No, leave the actual root password you're setting for your ESXi host but remove the "password" variable in the python snippet
where are the esxi install logs located? Its still not joinin the domain
here is partially what is in the kickstart file
The ESXi installation logs are in /var/log/esxi_install.log but again you won't see much in there because this is going through a different method of calling the API.
Can you confirm that the credentials you're using do work? I also mentioned in the blog post that your ESXi host must have FQDN when trying to join to an AD domain else you'll get an error. Please verify both of these
Can you also run "hostname" command to ensure that it's getting the correct hostname and it's FQDN? If that works out, the only other thing I can suggest is try building your ESXi host and then manually running this script to ensure the domain join process works. When you're running it manually, you will need to update the "password" variable with the actual root password of your ESXi host. Give that a try and let me know if the domain join process works, you may also want to open vSphere Client so you can see the task and if there are errors.
hostname does show the FQDN of the server.
I noticed that when i browse to
https://server/mob/?moid=ha-ad-auth&method=joinDomain
it is prompting for authentication. which is the local root password of the server.
Yes, that is correct, it needs the local root password of the ESXi host which is exactly what the domain script is doing. Are you sure you're passing in the right credentials?
A 401 code generally means that you've not authenticated properly and you get the unauthorized error message.
its failing to authenticate thats the problem.
the default password is not blank in my kickstart file. Its changed with the
rootpw --iscrypted $1$vP/2Aaii$p3x/2htjd5BragreMltBZ/
could this be a problem.
I tried adding the password to the python script (clear text) but still no go
As I had already mentioned, the password is irreleveant during the build process, there is a post script that VMware runs to actually take the encrypted hash and update the actual root password. During the installation, there is no root password and thats why you're authenticating to the MOB with a blank for the root pass. To me it sounds like something is still occuring that is causing your 401 issue
Here is the kickstart snippet in my dev enviornment:
%firstboot --unsupported --interpreter=busybox
vim-cmd hostsvc/enable_remote_tsm
vim-cmd hostsvc/start_remote_tsm
vim-cmd hostsvc/enable_local_tsm
vim-cmd hostsvc/start_local_tsmcat > /tmp/joinActiveDirectory.py << __JOIN_AD__
import sys,re,os,urllib,urllib2# connection info to MOB
url = "https://localhost/mob/?moid=ha-ad-auth&method=joinDomain"
username = "root"
password = ""
domainname = "primp-industries.com"
ad_username = "administrator"
ad_password = "SuperDuperSecretPasswordYo"#auth
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None,url,username,password)
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)#execute method
params = {'domainName':domainname,'userName':ad_username,'password':ad_password}
e_params = urllib.urlencode(params)
req = urllib2.Request(url,e_params)
page = urllib2.urlopen(req).read()
__JOIN_AD__python /tmp/joinActiveDirectory.py
Has anybody tried this on ESX Classic?
Seems to work fine on ESXi, but on classic I get this error "raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
urllib2.HTTPError: HTTP Error 403: Forbidden: Possible Cross-Site Request Forgery"
Thanks.
i still cannot get it to work on esxi. For esxi I got the error you are getting in classic.
I am using 4.1u1 build 348481
I didn't track it to the exact patch, but one of the pre v4.1 Update 1 patches added detection for "Possible Cross-Site Request Forgery"
I setup my mob to run over http, did some network captures, and determined that the following needed to be included:
1. Session cookie
2. Hidden form / value for 'vmware-session-nonce'
I'm not a python guru, so if you have a better way to do what I've done, please contribute back to this thread.
The following code is working for me (at least post-install, I'll trying during scripted installation shortly).
I sure hope this helps somebody else, as it was a challenge to resolve.
Enjoy!
import sys,re,os,urllib,urllib2,base64
### Define Variables ###
print 'Begin executing join domain script'
# mob url
url = "https://localhost/mob/?moid=ha-ad-auth&method=joinDomain"# mob login credentials -- use password = "" for build scripting
username = "root"
password = ""# which domain to join, and associated OU
domainname = "my.domain.com/VMWare Server OU"# Active Directory credentials with rights to join a computer to the domain
# create encoded password with the command: python -c "import base64; print base64.b64encode('mypassword')"
# note: escape special characters in your password with a \
# Feel free to improve this solution, but it at least keeps cleartext out of the file.
ad_username = "user@my.domain.com"
encodedpassword = "cGFzc3dvcmQ="
ad_password = base64.b64decode(encodedpassword)# Create global variables
global passman,authhandler,opener,req,page,page_content,nonce,headers,cookie,params,e_params# Code to build opener with HTTP Basic Authentication
try:
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None,url,username,password)
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)
except IOError, e:
if hasattr(e, 'reason'):
print 'FAIL: HTTP Authentication'
print 'Reason: ', e.reason
sys.exit(1)
elif hasattr(e, 'code'):
print 'FAIL: HTTP Authentication'
print 'Error code: ', e.code
sys.exit(1)
else:
print 'SUCCESS: Build HTTP Basic Authentication Handler'
### Code to capture required page data and cookie required for post back to meet CSRF requirements ###
try:
req = urllib2.Request(url)
page = urllib2.urlopen(req)
page_content= page.read()
except IOError, e:
if hasattr(e, 'reason'):
print 'FAIL: MOB Page Request'
print 'Reason: ', e.reason
sys.exit(1)
elif hasattr(e, 'code'):
print 'FAIL: MOB Page Request'
print 'Error code: ', e.code
sys.exit(1)
else:
print 'SUCCESS: Request MOB page data'# regex to get the vmware-session-nonce value from the hidden form entry
reg = re.compile('name="vmware-session-nonce" type="hidden" value="?([^\s^"]+)"')
nonce = reg.search(page_content).group(1)# get the page headers to capture the cookie
headers = page.info()
cookie = headers.get("Set-Cookie")# Code to join the domain
try:
params = {'vmware-session-nonce':nonce,'domainName':domainname,'userName':ad_username,'password':ad_password}
e_params = urllib.urlencode(params)
req = urllib2.Request(url, e_params, headers={"Cookie":cookie})
page = urllib2.urlopen(req).read()
except IOError, e:
if hasattr(e, 'reason'):
print 'FAIL: MOB Page Request'
print 'Reason: ', e.reason
sys.exit(1)
elif hasattr(e, 'code'):
print 'FAIL: MOB Page Request'
print 'Error code: ', e.code
sys.exit(1)
else:
print 'SUCCESS: Host joined to the domain'
Good work klich! This worked for me. Also, its nice that the AD password is no longer in clear text and you can specify an OU
Hi klich,
Thanks for sharing this information, I've gone ahead and updated my original log post with your modified code - http://www.virtuallyghetto.com/2011/02/automating-active-directory-domain-join.html