Skip to main content

Command Palette

Search for a command to run...

Setting Up a Temporary User with an Expiry Date

Updated
5 min read
Y
Hi, I’m Yvette — a Berlin-based platform-oriented engineer transitioning into junior roles in platform engineering, DevOps, cloud operations, developer tooling, and observability. This blog is my technical notebook. I write about what I’m learning and building across platform engineering, developer experience, CI/CD automation, cloud operations, APIs, and observability. I care about clarity, reducing noise, and building systems that make work simpler for both users and developers. I’m currently looking for junior or entry-level opportunities where I can continue growing in these areas while contributing to better developer workflows and reliable infrastructure.

Part of my #DevOpsFromZero series — documenting real KodeCloud tasks with the commands, the reasoning, the mistakes, and the principles behind every decision.


The Task

Create a user named mariyam on App Server 3. Set the expiry date to 2027-02-17, ensuring the user is created in lowercase as per standard protocol.


Why Would You Ever Need a User with an Expiry Date?

Some users don't need permanent access. Think of auditors, contractors, or project members brought in for a fixed duration. Once their engagement ends, their access should end with it.

Think of it like giving a contractor a visitor badge that automatically stops working on their last day — rather than depending on someone to cut access who may forget or not be available within that time to do so.

This is automation over human memory. Systems shouldn't rely on someone remembering to revoke access. Setting an expiry date enforces it automatically, with no manual intervention required.

Real-world cases where this matters:

  • An external auditor who needs read access for two weeks

  • A contractor joining for a fixed-term project

  • An internal team member temporarily elevated for a specific task


The Infrastructure

App Server 3 details from the Nautilus project environment:

Detail Value
Hostname stapp03
SSH User banner

Connect via:

ssh banner@stapp03

Step-by-Step: What I Did

1. Connect and Check Context

whoami
# banner

Not root — sudo will be needed for user management.

2. Create the User with an Expiry Date

The useradd command supports the -e flag to set an account expiry date:

sudo useradd -e 2027-02-17 mariyam

No output. No errors. But — as the previous task taught me — that doesn't mean it worked correctly.

3. Verify the Expiry Date

/etc/passwd stores shell and home directory information, but not account ageing details. For that, you need chage:

sudo chage -l mariyam

Output:

Last password change                : Jun 19, 2026
Password expires                    : never
Password inactive                   : never
Account expires                     : Feb 17, 2027
Minimum number of days between password change  : 0
Maximum number of days between password change  : 99999
Number of days of warning before password expires: 7

The Account expires line confirms the date was set correctly. Task complete. ✅


The Mistake: Silent Failure and Wrong Date Format

This is the most important part of this task.

I tested what happens when you pass the date in the wrong format — YYYY-DD-MM instead of YYYY-MM-DD:

sudo useradd -e 2027-28-03 ravi

No error. The command completed silently. But when I verified:

sudo chage -l ravi
# Account expires : Apr 03, 2029

Linux didn't reject the wrong format. It silently interpreted it differently and set a completely unintended expiry date — two years off from what was intended.

This is one of the most dangerous categories of bugs in engineering: silent failure. No warning. No error. Just wrong behaviour quietly running in production.

💡 The rule: Always use YYYY-MM-DD. Always verify with chage -l after creation. Never trust a clean exit code alone.


Why YYYY-MM-DD? The ISO 8601 Standard

The -e flag expects dates in ISO 8601 format — YYYY-MM-DD. This isn't arbitrary:

  • No ambiguity: 04-03-2027 could mean April 3rd or March 4th depending on where you're from. 2027-04-03 means exactly one thing everywhere.

  • Lexicographical sorting: Dates starting with the year sort correctly as plain text — useful for logs, filenames, and system utilities.

  • Big-endian consistency: Year → Month → Day goes from largest to smallest unit, the same way computers process numbers.

When in doubt: year first, always.


A Note on chage Permissions

Running chage -l without sudo returns a permission error:

chage -l mariyam
# chage: Permission denied.

Account ageing information is privileged. You need sudo — or root — to read it.


Key Concepts Recap

Concept What It Means
Account expiry The date after which a user can no longer log in
useradd -e Sets the expiry date at user creation
chage -l Displays account ageing information for a user
ISO 8601 The YYYY-MM-DD date standard used by Linux
Silent failure A command that completes without error but produces unintended behaviour
Automation over memory Systems enforce access revocation — not humans

Closing Thought

Day 1 taught me: not every mistake requires deletion — modify deliberately.

Day 2 adds to that: no error doesn't mean correct behaviour. Silent failures are the hardest bugs to catch because they don't announce themselves.

Verify everything. The two seconds it takes to run chage -l is cheaper than debugging an account that expired two years too late — or two years too early.


#DevOpsFromZero #100DaysOfDevOps #Linux #DevOps #KodeCloud #Beginner

5 views

DevOps From Zero

Part 2 of 3

A 100-day journey through real DevOps tasks on KodeCloud #100daysofDevOps— documenting the commands, the reasoning, the mistakes, and the principles behind every decision. No polish, just progress.

Up next

Setting Up a Linux User with a Non-Interactive Shell

This is Day 1 of my #100DaysOfDevOps series on KodeCloud. The Task Create a user named john with a non-interactive shell on App Server 2. Simple on the surface. But before touching the server, it's