# ansible / provisioning / users
Provision Users & Workspaces from scratch
A foundational playbook that installs prerequisites, provisions a new system user, scaffolds their home directory, and safely seeds it with configuration files in a single pass.
Why this playbook holds up
When onboarding new services or users, manual folder creation and permission setting frequently leads to "Access Denied" errors down the road. This playbook locks down the configuration as code, guaranteeing the environment is built perfectly every time.
Strict Ownership
Every file and directory explicitly defines owner, group, and mode, ensuring the new user has exact access without relying on default umasks.
Idempotent Scaffolding
If the user or files already exist, Ansible simply verifies their permissions rather than overwriting or duplicating them, preventing accidental data loss.
The full task list
--- - name: Install package and setup user environment hosts: localhost become: yes tasks: - name: Install tree apt: name: tree state: present - name: Create user user: name: ai state: present create_home: yes shell: /bin/bash - name: Create directory file: path: /home/ai/shan state: directory owner: ai group: ai mode: '0755' - name: Create file file: path: /home/ai/shan/welcome.txt state: touch mode: '0644' - name: Copy file copy: src: /home/ak/Downloads/update.yml dest: /home/ai/update.yml owner: ai group: ai mode: '0644'
Run order
- package
Installs the
apttreecommand-line utility via the APT package manager. - identity
Provisions the
useraiuser, generates their home directory, and assigns bash as their shell. - scaffold
Creates a nested directory (
fileshan) and touches an empty placeholder file inside it. - seed
Copies a playbook from the host's download folder into the new user's environment.
copy
Check the user environment
To ensure the playbook executed correctly, you can verify the user's existence and use the newly installed tree package to inspect the file hierarchy and permissions.
Lessons from running this in production
YAML indentation is strict! Your original copy task had misaligned spacing on the src and dest lines. I have fixed it in this generated playbook to ensure it runs without errors.
Using state: touch with the file module works identically to the Linux touch command: it creates an empty file if it doesn't exist, but only updates the timestamp if it does.
Declaring owner and group on the copy module is a great best practice to prevent files copied by root from becoming unreadable to the destination user.