Now that we’ve provisioned our droplet with Terraform, it’s time to create a proper admin user. It’s bad practice to SSH into a server as root
, so we’ll create a limited user with sudo privileges for day-to-day admin tasks.
We’ll use Ansible to automate this step, just like a real production environment.
📁 Step 1: Set Up the Ansible Directory
Next to your terraform
folder, create an ansible
folder and move into it:
mkdir ansible && cd ansible
Create a file named create-sudo-user.yml
:
⚙️ Step 2: Create the Admin User Playbook
We’ll create an Ansible playbook to:
- Ensure the
sudo
group exists - Allow passwordless sudo for that group
- Create an
admin
user and assign it to the group - Set up SSH access for the user
# create-sudo-user.yml
---
- hosts: all
gather_facts: false
tasks:
- name: Make sure we have a 'sudo' group
group:
name: sudo
state: present
- name: Allow 'sudo' group to have passwordless sudo
lineinfile:
dest: /etc/sudoers
state: present
regexp: '^%sudo'
line: '%sudo ALL=(ALL) NOPASSWD: ALL'
validate: 'visudo -cf %s'
- name: Create admin user
user:
name: admin
state: present
shell: /bin/bash
create_home: yes
groups: sudo
append: yes
- name: Create SSH directory for admin user
file:
path: "/home/admin/.ssh"
state: directory
mode: "0700"
owner: admin
group: admin
- name: Add SSH key for admin
authorized_key:
user: admin
state: present
key: "{{ lookup('file', '~/.ssh/tutorial.pub') }}"
🧩 Breaking it down
✅ Create the sudo
group
- name: Make sure we have a 'sudo' group
group:
name: sudo
state: present
We make sure the sudo
group exists. On most Debian-based systems (like Ubuntu), this is the group used for granting admin privileges.
🔐 Allow passwordless sudo
- name: Allow 'sudo' group to have passwordless sudo
lineinfile:
dest: /etc/sudoers
state: present
regexp: '^%sudo'
line: '%sudo ALL=(ALL) NOPASSWD: ALL'
validate: 'visudo -cf %s'
This modifies the /etc/sudoers
file to allow any user in the sudo
group to run commands without being prompted for a password. The validate
line ensures we don’t break sudo permissions by mistake—it checks the file before applying the change.
👤 Create the admin
user
- name: Create admin user
user:
name: admin
state: present
shell: /bin/bash
create_home: yes
groups: sudo
append: yes
This creates our admin
user and adds them to the sudo
group. We also ensure they get a home directory and use Bash as their default shell.
📁 Set up the .ssh
directory
- name: Create SSH directory for admin user
file:
path: "/home/admin/.ssh"
state: directory
mode: "0700"
owner: admin
group: admin
We prepare the SSH directory with proper permissions so the public key can be added securely.
🔑 Add your public key
- name: Add SSH key for admin
authorized_key:
user: admin
state: present
key: "{{ lookup('file', '~/.ssh/tutorial.pub') }}"
This copies your public key to the server so that you can SSH in as the admin
user. Make sure ~/.ssh/tutorial.pub
exists on your local machine—it should be the same key you used with Terraform.
🧭 Step 3: Point Ansible to the Droplet
Create an inventory file with your droplet’s IP:
echo "<your-droplet-ip>" > inventory
🚀 Step 4: Run the Playbook
You can now apply the Ansible configuration like this:
ansible-playbook -i inventory create-sudo-user.yml -u root
Or, create a handy alias to shorten the command:
echo 'alias play="ansible-playbook -i inventory" >> ~/.zshrc
source .zshrc
play create-sudo-user.yml -u root
✅ Done!
You’ve now created a secure, limited admin
user with passwordless sudo access and your SSH key added for login.
🔜 Next Up: Security Hardening & Ansible Roles
In the next post, we’ll:
- Set up some essential security best practices (
fail2ban
, unattended upgrades) - Refactor our Ansible code using roles for better organization
Stay tuned 👋
Leave a Reply