CloudTadaInsights

Adding ESXi 7 to vCenter Server and Cloud Foundation for Non-Root Users

Adding ESXi 7 to vCenter Server and Cloud Foundation for Non-Root Users

1. Why Add an Admin User Instead of Using Root?

  1. Linux operating systems use the root user as the full authority account, and all administrative users know this account exists.

  2. In Data Center Virtualization (DCV) environments such as vCenter Server (VCSA) or Cloud Foundation (SDDC), using shared root accounts is a mistake because it creates difficulties for IT audits.

  3. The root user not only has full administrative control (AFC) of ESXi but also serves as the connection for Add Host to Inventory > Host Cluster of vCenter, Cloud Foundation, Veeam Backup & Replication (VBR), Commvault Server (CS), NAS storage that needs to connect and mount data stores to ESXi, etc.

  4. IT security processes often include changing passwords for the root account at scheduled times or unexpectedly, all of which affect VM control, host connections in the Inventory of VCSA or SDDC, VBR, CS, NAS, etc.

In summary:

  • This is a security issue for DCV systems.
  • The goal to limit the use of root users with administrative roles is obvious.
  • Replacing with a different Admin account that maintains the connection between ESXi and VCSA/SDDC and storage arrays is the recommended approach.

2. Method 1: Adding an Account Belonging to the LocalOS Group on the ESXi Host and Elevating Admin Rights

In ESXi 7.0, users are required to configure additional authorization to be used for adding the ESXi host to vCenter Server.

When attempting to add ESXi version 7.0+ hosts to vCenter Server with a custom non-root user, the following error was received:

"System Error!" and "Status" is "Cannot complete login due to incorrect username or password."

ESXi Connection

ESXi Authentication Error Details

Steps to resolve this issue:

Step 1.

  • New users are not created by this script; we must follow the procedure to create new users and assign administrative privileges as applied to previous ESXi versions.

ESXi Host Successfully Added to vCenter Inventory

Changing Root Password on ESXi Host

Root Access Status After Password Change

Step 2:

  • Prepare the attached script (in the file) "esxi_new_admin.py" with the following .py code:
PYTHON
#!/usr/bin/python
import atexit
import argparse
import getpass
import ssl
import sys

from pyVmomi import vim, vmodl
from pyVim.connect import SmartConnect, Disconnect

def get_args():
    parser = argparse.ArgumentParser(description='Configure ESXi for non-root user and Lockdown Mode')
    parser.add_argument('-s', '--host', required=True, help='IP of the ESXi host')
    parser.add_argument('-u', '--user', required=True, help='Root user to connect initially')
    parser.add_argument('-n', '--new_user', required=True, help='Name of the new user to create (e.g., svc_vcenter)')
    parser.add_argument('-p', '--new_pass', required=True, help='Password for the new user')
    
    args = parser.parse_args()
    # Securely enter root password
    args.root_pass = getpass.getpass(prompt='Enter root password: ')
    return args

def create_user_with_minimal_privileges(content, username, password):
    """
    Create user, new role (minimal privileges) and assign permissions.
    """
    auth_manager = content.authorizationManager
    user_manager = content.user_manager

    # 1. Create user
    print(f"[*] Creating user: {username}...")
    try:
        user_manager.CreateUser(username, password, None)
        print(f"[+] User {username} has been created.")
    except vmodl.fault.AlreadyExists:
        print(f"[!] User {username} already exists. Skipping user creation.")
    except Exception as e:
        print(f"[!] Error creating user: {e}")
        sys.exit(1)

    # 2. Create new Role with minimum privileges (Minimal Privileges)
    # vCenter requires this permission to create the vpxuser and manage the host.
    role_name = "vCenterAdminMinimal"
    
    # List of required privileges (Important: Host.Local.ManageUserGroups)
    required_privileges = [
        'Host.Config.*',           # Configure host
        'Host.Cim.*',              # Hardware management (CIM)
        'Host.Inventory.*',        # Manage inventory
        'Host.Local.ManageUserGroups', # REQUIRED: To create vpxuser
        'System.Read',
        'System.Write'
    ]
    
    # Check if role already exists
    role_id = None
    for role in auth_manager.role_list:
        if role.name == role_name:
            role_id = role.roleId
            print(f"[!] Role '{role_name}' already exists. Using existing role.")
            break
    
    if role_id is None:
        print(f"[*] Creating new Role: {role_name}...")
        try:
            # Map string privilege to object privilege id
            priv_ids = []
            avail_privs = auth_manager.privilege_list
            priv_dict = {p.name: p.privId for p in avail_privs}
            
            for p in required_privileges:
                if p in priv_dict:
                    priv_ids.append(priv_dict[p])
                elif '*' in p:
                    # Handle wildcard (e.g., Host.Config.*)
                    base = p.replace('*', '')
                    for key in priv_dict:
                        if key.startswith(base):
                            priv_ids.append(priv_dict[key])

            auth_manager.AddRole(role_name, priv_ids)
            role_id = next(r.roleId for r in auth_manager.role_list if r.name == role_name)
            print(f"[+] Role '{role_name}' has been created with {len(priv_ids)} privileges.")
        except Exception as e:
            print(f"[!] Error creating role: {e}")
            sys.exit(1)

    # 3. Assign Role to User on Root Folder
    print(f"[*] Assigning permissions to user {username}...")
    perm = vim.Permission()
    perm.principal = username
    perm.group = False
    perm.roleId = role_id
    perm.propagate = True
    
    try:
        auth_manager.SetEntityPermissions(content.rootFolder, [perm])
        print(f"[+] Permissions assigned successfully.")
    except Exception as e:
        print(f"[!] Error assigning permissions: {e}")
        sys.exit(1)

def configure_lockdown_mode(host_system, username):
    """
    Configure Lockdown Mode and add user to Exception List.
    """
    print("[*] Configuring Lockdown Mode...")
    
    # Get Access Manager
    host_config_manager = host_system.configManager
    access_manager = host_config_manager.hostAccessManager
    
    # Get current exception list
    # Note: You might need to change user to domain\user if using domain
    current_exceptions = list(access_manager.exceptionUsers) if access_manager.exceptionUsers else []
    
    if username not in current_exceptions:
        current_exceptions.append(username)
        print(f"[*] Adding user {username} to the exception list...")
    
    # Update Exception List before enabling Lockdown (If not, the user might be blocked immediately)
    try:
        access_manager.UpdateLockdownExceptions(current_exceptions)
        print("[+] Updated Exception List.")
    except Exception as e:
        print(f"[!] Warning: Could not update exception list: {e}")
        print("[!] If Lockdown is enabled, the user might be blocked. Please check manually.")

    # Enable Lockdown Mode (lockdownNormal)
    try:
        # State: lockdownNormal (Normal), lockdownStrict (Strict)
        access_manager.ChangeLockdownMode("lockdownNormal")
        print("[+] Enabled Lockdown Mode (lockdownNormal).")
        print("[+] Root account has been locked directly.")
    except Exception as e:
        print(f"[!] Error enabling Lockdown Mode: {e}")

def main():
    args = get_args()
    
    # SSL context ignoring verify (for Lab environment)
    context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
    context.verify_mode = ssl.CERT_NONE

    # Connect to ESXi using ROOT
    try:
        si = SmartConnect(host=args.host, user=args.user, pwd=args.root_pass, sslContext=context)
        atexit.register(Disconnect, si)
        content = si.RetrieveContent()
        
        # Get Host System object (Get first host in the list)
        host_system = content.rootFolder.childEntity[0].hostFolder.childEntity[0].hostFolder.childEntity[0].host[0]
        
        # 1. Create User & Role
        create_user_with_minimal_privileges(content, args.new_user, args.new_pass)
        
        # 2. Configure Lockdown Mode
        configure_lockdown_mode(host_system, args.new_user)
        
        print("\n" + "="*50)
        print("SUCCESS! System has been configured securely.")
        print("Please use the information below to add host to vCenter:")
        print(f"Host IP: {args.host}")
        print(f"Username: {args.new_user}")
        print(f"Password: {args.new_pass}")
        print("="*50)

    except vmodl.MethodFault as e:
        print(f"[!] vAPI/VMware Error: {e.msg}")
        sys.exit(1)
    except Exception as e:
        print(f"[!] Undefined Error: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()

Step 3. Use PuTTY/WINSCP to open SSH and upload the script esxi_new_admin.py to the '/' directory on the ESXi host.

  • Use SSH to connect to the ESXi host as root, see Using ESXi Shell in ESXi 5.x, 6.x and 7.x.

ESXi Shell Connection Interface

  • Run the uploaded script by executing the command:
TEXT
python /esxi_new_admin.py

ESXi LocalOS User Configuration Process

When prompted by the script, provide the new username and password for the "root" user.

For example, here User5 is the user we manually created as part of the LocalOS group on ESXi.

Step 4. Verify Admin Access Rights to ESXi for the New User:

Root User Demoted to Read-Only Access Rights

  • Test adding the host to the VCSA inventory using the new user:

AD User Admin Privileges Configuration Screen

  • Successfully added the host using the new user.

AD User Login Process in vCenter

  • Now change the ESXi root password to demonstrate that the root user does not affect the new user with admin rights.

  • Example: Reduce privileges of the root user on the ESXi host

Adding Host to vCenter with AD User Interface

Or

  • Change the password of the root user

Successfully Added Host to VCSA Inventory Confirmation

VMware Security Implementation Summary

  • After successfully changing the root user password, we will log out from the new user and log back in using the root user with the old password

Security Implementation Best Practices Guide

  • Correct login and access rights are read-only

Active Directory Security Benefits Overview

3. Method 2: Adding an Account Belonging to the Admin User Group on the ESXi Host and Elevating Admin Rights

Step 1. - On the AD Server, add users:

Root User Security Risks and Vulnerabilities

Example: user4, domain: vclass.local, vclass\user4 is a member or not a member of the Group: ESX Admins

Step 2. esxi03.vclass.local is domain joined

ESXi Host Disconnection Process

Step 3. Then log in using user: [email protected]

VCenter Management Activities Monitoring

Step 4. Next is permission assignment, the ESX Admin Group on the AD server will be automatically assigned to the group

Removing Host from vCenter Inventory Process

Step 5. Note that if you use WinSCP/PuTTY to log in with the root user now, you no longer have privileges because root has been demoted to read-only

Host Inventory Management Interface

Performance Metrics and Considerations Dashboard

  • Now you must use the AD user that has been automatically assigned admin privileges from the ESX Admins group to log in

Historical Data Preservation in vCenter

And connect to ESXi using WinSCP/PuTTY

VMware Infrastructure Security Overview

Enter the new AD user that was automatically added from the ESX Admins group:

Security Implementation Configuration

Step 6. Add host to vCenter using AD User

Final Security Configuration Completed

  • We have successfully added the host to the VCSA 7 inventory using a new AD User that is not related to the root user.

VMware Security Best Practices Summary

Summary:

  • Of the two methods above, using AD User is the best approach because it provides security and is separate from ESXi and is secured with MS AD-DC encryption.

  • Passwords should be at least 8-16 characters long with uppercase, lowercase, numbers, and special characters.

  • Account names should be in the form "SystemAccountServices" and should not have periodic password changes ("Password age") enabled, or be used for personal administration ("Personal account"), but should only be used to maintain connections between ESXi and VCSA/SDDC, etc.

Wishing you success and safety in configuring and operating secure DCV deployments!

Evidence of the harm of using the ESXi root user to add hosts to vCenter or SDDC:

From the famous virtualization book "Mastering vSphere 6.7"

Configuring and Managing vSphere 6.7

Chapter 5

When you enter the root password to add the host to the vCenter, the password is used to establish a connection with the host and to install the vCenter agent. The process sets different credentials that maintain the communication and authentication between ESXi and vCenter, even if ESXi's root password is changed.

Disconnecting a host from vCenter Server

Once ESXi is connected to vCenter Server, you can always disconnect or remove the host later on. It's important to understand that disconnecting the host from vCenter Server is different from removing the host. Disconnecting a managed host from vCenter Server doesn't remove ESXi from the VCenter Inventory as well as the VMs registered on the host. When the managed host is disconnected, vCenter Server suspends monitoring and management activities for that host. If you disconnect a host and then connect it again, all the performance metrics will be kept.

It's a different story if you remove the host from the vCenter Server. Removing a managed host from the vCenter Server means the host and its VMs are removed from the vCenter Inventory. If you remove a host from the inventory and then add it again, it will be considered a new object and no historical performance metrics will be available.

VMware Infrastructure Security Implementation Results

References

  1. Adding ESXi 7 to vCenter Server with Non-Root User
  2. Thêm ESXi 7 vào vCenter Server và Cloud Foundation với người dùng không phải root

You might also like

Browse all articles

Lesson 4: Infrastructure Preparation for PostgreSQL HA

Setting up the infrastructure for PostgreSQL High Availability with Patroni and etcd, including hardware requirements, network configuration, firewall, SSH keys, and time synchronization.

#Database#PostgreSQL#Infrastructure
Series

PostgreSQL Security Hardening Guide

Essential security features and hardening measures for PostgreSQL HA cluster deployment with Patroni, etcd, and PgBouncer. Follow this guide for production security best practices.

#Database#PostgreSQL#Security

Lecture 0: Securing Accounts

Introduction to cybersecurity focusing on securing accounts with authentication, passwords, 2FA, and protection against various attacks.

#Authentication#Authorization#Passwords

Lesson 3: Introduction to Patroni and etcd

Understanding Patroni and etcd for PostgreSQL High Availability, including DCS, Raft consensus algorithm, leader election, and split-brain prevention mechanisms.

#Database#PostgreSQL#Patroni

Lesson 2: PostgreSQL Streaming Replication

Deep dive into PostgreSQL Streaming Replication, covering WAL mechanisms, synchronous vs asynchronous replication, replication slots, and hands-on lab setup.

#Database#PostgreSQL#Replication