352 labs to replay on your own machine, graded on the real state of the system rather than on the commands you typed. They prepare 8 certifications, from RHCSA to CKS, and add up to roughly 220 hours of practice. Everything is free and account-free: the catalogues are public repositories, and the grading runs on your machine.
The search box takes a command, a skill or
a certification acronym: typing selinux or
CKA narrows the list down to what concerns you. Every lab is
written in English. The companion guides are being
translated, and a link says when one is still French only.
Three commands to run any of them
- Install the CLI, then add the catalogue the lab
belongs to. The exact command sits at the top of each catalogue below.
dsoxlab catalog add https://github.com/stephrobert/linux-dsoxlab-training - Check your machine. This reports what is missing,
memory or hypervisor, before Terraform fails on you.
dsoxlab doctor - Run the lab by its id, the one shown next to every
row of the catalogue.
startprepares the environment and opens a session inside it;checkruns the tests and computes your score.dsoxlab start l1-first-terminaldsoxlab check l1-first-terminal
- 352labs
- 5catalogues
- 8certifications
- 220hours of practice
Linux, RHCSA and LFCS
Add this catalogue dsoxlab catalog add https://github.com/stephrobert/linux-dsoxlab-training
Fundamentals
-
First steps in the terminal
Run basic commands (whoami, pwd, hostname, date) and capture the output in a file.
dsoxlab start l1-first-terminal -
Map Linux: kernel, distribution and key directories
Explore what Linux is made of: run real commands on your own system to discover the kernel, your distribution and the role of /etc, /var/log and /proc. Fill in a knowledge map.
dsoxlab start l1-discover-linux-map -
Choose your reference Linux distribution
Compare Debian/Ubuntu and RHEL-based distributions, understand the criteria for choosing between them, and document your choice for three practical scenarios.
dsoxlab start l1-choose-distro -
Identify your Linux machine
Run commands to collect your system's hostname, distribution, kernel version and IP address. Produce a machine identity card stored in vm-info.txt.
dsoxlab start l1-prepare-vm -
Read and decode a command
Decompose 5 Linux commands into their command/options/arguments parts and fix 3 broken commands.
dsoxlab start l1-read-a-command -
Get help from the command line
Use man, --help, and apropos to find the right command options without searching the web.
dsoxlab start l1-get-help -
Linux filesystem hierarchy (FHS)
Match the standard Linux directories to their roles and classify files by location.
dsoxlab start l1-linux-filesystem -
Navigate the filesystem
Use cd, ls, mkdir, cp, mv, rm to build a target directory tree from scratch.
dsoxlab start l1-navigate-filesystem -
Absolute and relative paths
Copy a file using an absolute path and a relative path, then solve 5 path navigation puzzles.
dsoxlab start l1-paths-absolute-relative -
Redirect streams and chain commands with pipes
Redirect stdout and stderr, merge them, and chain commands with pipes to produce exact artifacts.
dsoxlab start l1-redirections-pipes -
Filter a log with grep and regular expressions
Use grep with anchors, character classes, invert-match and count to extract exact facts from an access log.
dsoxlab start l1-grep-regex -
Transform and aggregate text with cut, sort, uniq, sed and awk
Slice columns, deduplicate, count occurrences, sum a field and rewrite a delimiter to turn a raw record file into exact facts.
dsoxlab start l1-text-processing -
Locate files with find by name, size and permissions
Extract a project tree and use find to list files by name pattern, by size and by exact permissions , producing the results into files that are checked against the real tree.
dsoxlab start l1-find-files -
Archive, compress and selectively extract with tar, gzip and bzip2
Create gzip and bzip2 tarballs, list their contents, and extract a single member into a target directory.
dsoxlab start l1-tar-archives -
Set exact file permissions with chmod (octal and symbolic)
Give each file the right owner/group/other bits: a private secret, an executable script, a group-readable note and a private directory.
dsoxlab start l1-permissions-ugo -
Create hard and symbolic links and tell them apart
Make a hard link that shares the inode, a symbolic link that points by path, and a symlink to a directory , proven by inode, link count and link target.
dsoxlab start l1-links-hard-sym -
Write a first Bash script: variables, a loop and a condition
Write rapport.sh that reads a status file passed as an argument, counts UP/DOWN with a loop, prints them, and exits non-zero when any host is down.
dsoxlab start l1-bash-script -
Initialize a Git repo: commit, history and a branch
Create a repository, make two commits tracking real files, and open a feature branch , proven by inspecting the repository state itself.
dsoxlab start l1-git-basics -
Environment variables: export, PATH and a sourced env file
Write env.sh that, when sourced, exports variables, reuses one in another, and prepends a bin directory to PATH , proven by sourcing it in a subshell.
dsoxlab start l1-env-profiles -
Inspect a TLS certificate with openssl
Read a delivered X.509 certificate: extract its subject, validity dates, SHA-256 fingerprint and public key with openssl x509.
dsoxlab start l1-ssl-certificates
Operating and maintaining
-
Add and manage swap space
Create a secure swap file, activate it, make it persistent in /etc/fstab and tune vm.swappiness.
dsoxlab start l2-swap-management -
Mount a filesystem persistently by UUID in /etc/fstab
Mount a pre-formatted extra disk at /srv/data through /etc/fstab, referenced by UUID (not device name) so it survives a reboot, and prove the line with mount -a AND findmnt --verify.
dsoxlab start l2-fstab-persist-uuid -
Create GPT partitions on a disk with parted
Put a GPT label on the spare disk and carve two partitions (512 MiB and 1 GiB), then make the kernel re-read the table.
dsoxlab start l2-partition-gpt -
Create and label an XFS filesystem, then mount it
Format a prepared partition as XFS with a label, create a mount point and mount it , proven by the filesystem type, its label and the active mount.
dsoxlab start l2-filesystem-create-xfs -
Diagnose a full filesystem and reclaim space
A filesystem is full. Find the culprit with df/du, remove the junk without deleting the legitimate data, and bring usage back down.
dsoxlab start l2-disk-space-troubleshoot -
Tune a mount for performance with noatime (persistently)
A read-heavy filesystem wastes I/O writing access times. Add the noatime mount option, make it active and persistent in /etc/fstab.
dsoxlab start l2-storage-performance -
Extend a logical volume and prove the mount survives a reboot
Extend an LVM logical volume, grow the XFS filesystem, and make the mount persistent via /etc/fstab by UUID.
dsoxlab start l2-lvm-extend-persist -
Mount an NFS export persistently from a server
A second host exports an NFS share. Mount it on the client at /mnt/nfs, make it persistent in /etc/fstab with _netdev so it survives a reboot.
dsoxlab start l2-nfs-mount-persist -
Mount a filesystem on demand with autofs
Configure autofs so that accessing /autofs/data mounts the spare disk automatically, and unmounts it after idle , a master map plus a mount map.
dsoxlab start l2-autofs-ondemand -
Build a software RAID 1 with mdadm
Assemble two disks into a redundant RAID 1 array with mdadm, format and mount it, and make it persistent.
dsoxlab start l2-raid-mdadm -
Encrypt a disk with LUKS
Encrypt a block device with LUKS2, open it, put a filesystem on it, mount it and make it unlock at boot via crypttab.
dsoxlab start l2-luks-encryption -
Create a local account with exact UID, shell and groups
Onboard a user with a specific UID, home, login shell, a primary group and a supplementary group , the RHCSA account-creation drill.
dsoxlab start l2-user-lifecycle -
Enforce password aging and complexity policy
Set per-account password aging with chage, the system default max age in login.defs, and a minimum password length via pwquality.
dsoxlab start l2-password-policy -
Delegate limited sudo rights with a sudoers drop-in
Grant the operators group password-less sudo for systemctl only, via a validated /etc/sudoers.d drop-in , least privilege, not full root.
dsoxlab start l2-sudo-delegation -
Grant fine-grained access with POSIX ACLs
Go beyond ugo: give one user rw on a file and a group rx on a directory, with a default ACL so new files inherit it , using setfacl/getfacl.
dsoxlab start l2-acl-posix -
Set up a collaborative directory with the set-GID bit
Give a shared directory the devteam group and the set-GID bit so files created inside inherit the group , proven by the directory mode and a member's new file.
dsoxlab start l2-collaborative-setgid -
Install, remove and query packages with dnf
Bring the machine to a target software state: install a needed package, remove an unwanted one, and confirm with dnf/rpm queries.
dsoxlab start l2-package-management -
Configure a dnf repository with a .repo file
Add a software repository under /etc/yum.repos.d: an id, a baseurl, enabled and GPG-checked, then confirm dnf sees it.
dsoxlab start l2-repo-configure
Services and troubleshooting
-
Set the default systemd boot target
A server has no business booting into a graphical target. Set the default to multi-user.target and confirm it.
dsoxlab start l3-boot-target -
Add a persistent kernel boot parameter
Add a kernel command-line parameter to the current kernel with grubby and to /etc/default/grub for future kernels, so it survives reboots and updates , proven by grubby and the grub config.
dsoxlab start l3-grub-kernel-args -
Create and enable a systemd service unit
Wrap a program in a systemd .service unit, start it and enable it at boot , proven by the service being active, enabled and doing its job.
dsoxlab start l3-service-create-unit -
Diagnose and fix a systemd service stuck in a crash loop
A systemd service keeps restarting because of a missing config file. Use systemctl + journalctl to find the root cause and fix it permanently.
dsoxlab start l3-service-diagnose -
Make the systemd journal persistent across reboots
By default logs vanish on reboot. Enable persistent journald storage so /var/log/journal keeps history , proven by config, directory and a real journal file.
dsoxlab start l3-journald-persist -
Schedule a recurring job with cron
Run /usr/local/bin/report.sh every day at 02:30 through a cron entry , proven by the actual schedule the cron daemon will honour.
dsoxlab start l3-scheduling-cron -
Schedule a one-shot job with at
Queue a command to run once at a later time with at, and prove it is scheduled , the one-off counterpart to cron.
dsoxlab start l3-scheduling-at -
Schedule a recurring job with a systemd timer
Create a .service and its .timer (OnCalendar), enable it, and prove it is active and persistent , the systemd way to schedule recurring work.
dsoxlab start l3-scheduling-timers -
Set per-user resource limits (open files) with limits.d
Give the appuser account a higher open-files limit via /etc/security/limits.d , proven by the effective ulimit in a real login session.
dsoxlab start l3-app-constraints -
Harden kernel parameters persistently with sysctl.d
Disable IP forwarding and ICMP redirects via /etc/sysctl.d, applied now and surviving reboot , proven by the live sysctl values.
dsoxlab start l3-sysctl-persist -
Lower a service's scheduling priority with Nice
A batch worker hogs the CPU. Give its service a nice value of 10 so it yields to interactive work , proven by the live process priority and the unit config.
dsoxlab start l3-process-signals-priority -
Apply a tuned performance profile
Switch the active tuned profile to throughput-performance and make it stick , proven by the active profile the tuned daemon reports.
dsoxlab start l3-tuned-profile -
Recover a read-only mount caused by a broken fstab
A bad /etc/fstab option left /srv/data mounted read-only. Fix the entry, remount read-write, and make mount -a clean again.
dsoxlab start l3-fs-readonly-recover -
Repair a broken sshd config before it locks you out
A drop-in left an invalid directive: sshd -t fails, so the next reload or reboot would kill remote access. Fix the config, keep root login disabled, and reload cleanly.
dsoxlab start l3-ssh-access-recovery
Network, security and containers
-
Synchronize the clock with chrony and set the timezone, persistently
Enable and start chronyd, turn NTP on and set the timezone to Europe/Paris , surviving reboot, proven by the live service state and timedatectl.
dsoxlab start l4-ntp-sync -
Configure a persistent static IPv4 with NetworkManager
Create a NetworkManager connection with a static IPv4 (manual method) that survives reboot , proven by the on-disk profile and the live address.
dsoxlab start l4-network-static-persist -
Diagnose and restore a down network connection
A NetworkManager connection is configured but stays down and won't auto-start. Diagnose it, bring it up, and make it auto-connect , proven by the live state and autoconnect flag.
dsoxlab start l4-network-troubleshoot -
Open a firewalld service permanently
Allow the http service through firewalld so it holds now and after reload/reboot , proven by the runtime and permanent service lists, without ever closing ssh.
dsoxlab start l4-firewall-persist -
Set up hardened key-based SSH access for a service user
Give the deploy user key-based SSH login with correct ownership and permissions (.ssh 700, authorized_keys 600, owned by the user) , the classic trap that silently breaks key auth.
dsoxlab start l4-ssh-key-auth-harden -
Run a detached container with Podman
Pull an image and run a named container detached, and prove it is up , the Podman basics for RHCSA containers.
dsoxlab start l4-podman-basic -
Run a container as a systemd service with Quadlet (boot-persistent)
Define a Quadlet .container unit so a container starts at boot under systemd , proven by the active service, the running container and the on-disk unit.
dsoxlab start l4-podman-systemd-persist -
Manage container images: pull, tag, save and inspect
Pull an image from a registry, tag it, save it to an archive and inspect that archive with skopeo , the image-management skills for RHCSA containers.
dsoxlab start l4-podman-images -
Allow a service with SELinux: persistent boolean and labeled port
Turn on an SELinux boolean persistently and label a non-standard port so a service is allowed under enforcing SELinux , proven by getsebool and semanage port.
dsoxlab start l4-selinux-boolean-port -
Fix a file's SELinux context, persistently
Give a custom web directory the httpd_sys_content_t type with semanage fcontext + restorecon so it survives a relabel/reboot , proven by ls -Z and the fcontext rule.
dsoxlab start l4-selinux-context-fix -
Diagnose an SELinux denial (AVC) and fix it the right way
A web file has the wrong SELinux label so httpd is denied (403). Read the AVC in the audit log and restore the context , without disabling SELinux. Proven by the live context and a 200 response.
dsoxlab start l4-selinux-diagnose-avc -
Set up persistent NAT port forwarding with nftables
Enable IP forwarding and add an nftables nat table (DNAT port forward + masquerade) that survives reboot , proven by the live ruleset, sysctl and persistence files.
dsoxlab start l4-nat-portforward -
Authenticate Linux against an LDAP directory with SSSD
Configure SSSD on the client so a directory user (alice) resolves and can log in, against a 389 Directory Server , proven by getent, id and the active authselect profile.
dsoxlab start l4-ldap-integration -
Load-balance a web backend with HAProxy
Configure HAProxy on the front host to reverse-proxy and load-balance to a backend web server, persistently , proven by a request through the proxy returning the backend's page.
dsoxlab start l4-reverse-proxy-lb -
Aggregate links: an active-backup bond under a bridge with nmcli
Build an active-backup bond over two slave interfaces and put a bridge on top, persistently with NetworkManager , proven by the bonding state and the bridge port.
dsoxlab start l4-bridge-bonding
Debian and Ubuntu variants
-
Manage Debian packages with apt and dpkg
Install a package with apt, pin it with a hold so updates skip it, and identify which package owns a file , the Debian package-management skills for LFCS.
dsoxlab start lfcs-package-apt -
Open a service through the firewall with ufw
Allow the http service and enable ufw so it filters at boot, without ever locking out SSH , the Debian firewall counterpart to firewalld, proven by ufw status.
dsoxlab start lfcs-firewall-ufw -
Manage an AppArmor profile: switch it to complain mode
Put a loaded AppArmor profile into complain (learning) mode with aa-complain and prove it with aa-status , the Debian mandatory-access-control counterpart to SELinux.
dsoxlab start lfcs-apparmor -
Configure a static IP and route with netplan
Declare a static IPv4 address and a static route in a netplan file and apply it on a dedicated interface , the Debian/Ubuntu network configuration, proven by the live address and route.
dsoxlab start lfcs-netplan-static -
Enable XFS user quotas and enforce a limit
Format a dedicated disk as XFS, mount it with user quotas enabled persistently, and enforce a block quota on a user , proven by the live quota state and the enforced limit.
dsoxlab start lfcs-storage-quotas -
Mount an SMB/CIFS share persistently and safely
A second host serves an SMB share. Mount it on the client, make it persistent in /etc/fstab with _netdev, and keep the password out of the world-readable fstab by using a 0600 credentials file.
dsoxlab start lfcs-mount-cifs
Exam-condition drills
-
Drill , essential commands under exam conditions
5 tasks, 100 points, 20 minutes, no hints: find by size, build a frequency report, links, ownership and permissions, and split stdout from stderr. Playable on RHEL or Debian , the skills are identical.
dsoxlab start drill-essential-commands -
Drill , users, groups and delegation under exam conditions
5 tasks, 100 points, 20 minutes, no hints: create an account to exact specs, enforce password aging, build a collaborative directory, delegate sudo narrowly, and lock a departing account. Playable on RHEL or Debian , user management is identical.
dsoxlab start drill-users-groups -
Drill , systemd units, timers and scheduling under exam conditions
5 tasks, 100 points, 25 minutes, no hints: write a service unit with a restart policy, schedule a weekly timer, add a cron job, fix the default boot target, and mask a service for good. Playable on RHEL or Debian , systemd is systemd.
dsoxlab start drill-systemd -
Drill , partitions, LVM and swap under exam conditions
5 tasks, 100 points, 25 minutes, no hints: partition a disk in GPT, build an LVM stack, mount by UUID persistently, add swap, and extend a logical volume online. Playable on RHEL or Debian , parted, LVM and XFS are identical.
dsoxlab start drill-storage -
Drill , package management under exam conditions
5 tasks, 100 points, 20 minutes, no hints: install a package, freeze it against upgrades, find which package owns a file, list what a package installed, and remove one. The objective is shared by RHCSA and LFCS , only the tool changes (dnf or apt), and you use your distribution's.
dsoxlab start drill-packages -
Drill , firewall under exam conditions
5 tasks, 100 points, 20 minutes, no hints: bring the firewall up, open two ports so they survive a reload, keep SSH alive, and explicitly reject a port. The objective is shared by RHCSA and LFCS , only the tool changes (firewalld or ufw).
dsoxlab start drill-firewall -
Drill , SELinux under exam conditions
4 tasks, 100 points, 20 minutes, no hints: put SELinux back in enforcing for good, fix a file context so it survives a relabel, flip a boolean persistently, and label a non-standard port. RHCSA only , Debian uses AppArmor, see drill-apparmor.
dsoxlab start drill-selinux -
Drill , AppArmor under exam conditions
4 tasks, 100 points, 15 minutes, no hints: confirm AppArmor is up, put one profile in complain, and bring two others back to enforce. LFCS only , RHEL uses SELinux, see drill-selinux.
dsoxlab start drill-apparmor -
Drill , static networking under exam conditions
4 tasks, 100 points, 20 minutes, no hints: a static address, a static route and an MTU on a dedicated interface, plus local name resolution. The objective is shared by RHCSA and LFCS , only the tool changes (nmcli or netplan).
dsoxlab start drill-network
Capstones
-
Put a server into production: one mission, nine deliverables, one reboot
A fresh VM, a delivered application, and one mission: put it into service. Storage on LVM, service account, application on port 8080, SELinux port label and context, permanent firewall rule, persistent journal, hardened SSH, scheduled backup. Nothing is scored on the commands typed: every test reads observable state, and the last one reboots the machine and checks again. What does not survive the reboot scores zero.
dsoxlab start capstone-mise-en-production -
Broken server: the site is down, the symptom tells you nothing
A working internal site stops answering. The setup injects ONE fault among six, drawn at random, and never says which: stopped service, wrong port, closed firewall, SELinux context, docroot permissions, full filesystem. You diagnose, you repair, and the repair must survive a reboot. Scored purely on observable state, with three checks that reject the sledgehammer fixes: SELinux must stay enforcing, firewalld must stay running, and the docroot must not become world-writable.
dsoxlab start capstone-serveur-casse -
RHCSA EX200 mock exam , 20 tasks across 2 VMs
Performance-based RHCSA mock exam covering 10 RHCSA domains: storage (LVM, swap, NFS client), shell scripting, networking (static IP, firewalld), users/groups, ACLs, services (systemd units, timers, time client), SELinux (modes, contexts, booleans, port labels), software (DNF, Flatpak), boot recovery (rd.break root reset). 20 tasks scored on 100 points across 2 VMs (server + client). 70/100 to pass. No hints.
dsoxlab start rhcsa-mock-exam -
LFCS mock exam , 17 tasks on Ubuntu 24.04
Performance-based LFCS mock exam mapped task by task onto the published objectives of the 5 official domains: Essential Commands (20%: Git, service troubleshooting, disk space, SSL), Operations Deployment (25%), Users and Groups (10%: accounts and ACLs), Networking (25%), Storage (20%: LVM, automount, swap). 17 tasks scored on 100 points on a single Ubuntu VM. 70/100 to pass. No hints.
dsoxlab start lfcs-mock-exam
Ansible and the RHCE EX294
Add this catalogue dsoxlab catalog add https://github.com/stephrobert/ansible-training
Preparing the environment
-
Prepare Ansible managed nodes
Converge the 5 managed node prerequisites (Python 3, SSH, NOPASSWD sudo, chrony, SELinux) with an idempotent bootstrap playbook.
dsoxlab start bootstrap-prepare-managed-nodes
Discovering Ansible
-
Declarative vs imperative: why Ansible does not drift
Compare a Bash script that drifts on every run with a playbook that converges, and prove idempotence with changed=0 on the second pass.
dsoxlab start decouvrir-declaratif-vs-imperatif -
Ansible installation: verify your control node
Identify your install method, check the 8 binaries on PATH, the modules reachable via ansible-doc and the collections the repo relies on.
dsoxlab start decouvrir-installation-ansible -
ansible.cfg: precedence and critical options
Write a project ansible.cfg, check the active config with ansible-config dump, override an option by environment variable and enable a callback.
dsoxlab start decouvrir-configuration-ansible -
Ansible CLI: the 8 everyday commands
Chain ad-hoc runs, ansible-doc, ansible-config, ansible-inventory, ansible-galaxy, ansible-vault and ansible-lint across the lab.
dsoxlab start decouvrir-prise-en-main-cli
First steps
-
First playbook: install nginx on the webservers
Write a 5-task playbook (dnf, systemd, firewalld), read the PLAY RECAP, capture output with register and check idempotence on the second pass.
dsoxlab start premiers-pas-premier-playbook -
First steps with ansible-vault
Encrypt a secrets file with ansible-vault, consume it through vars_files and protect output with no_log and a 0600 .vault_password.
dsoxlab start premiers-pas-ansible-vault
Writing Ansible code
-
Plays and tasks: anatomy and execution order
Structure a play with pre_tasks, tasks, post_tasks and handlers, then prove the real execution order with timestamped marker files.
dsoxlab start ecrire-code-plays-et-tasks -
handlers: the restart-on-config-change pattern
Notify several handlers, decouple them with listen, force meta: flush_handlers and pair validate so an invalid config is never applied.
dsoxlab start ecrire-code-handlers -
tags: target or skip a subset of tasks
Set tags, target with --tags and exclude with --skip-tags, inspect the plan via --list-tasks and use the special always and never tags.
dsoxlab start ecrire-code-tags -
check mode and diff: dry-run and change preview
Run a playbook with --check --diff, spot the modules that do not support check, force check_mode: false and diagnose a false changed positive.
dsoxlab start ecrire-code-checkmode-diff -
Variables: declaration and scope
Declare variables with vars and vars_files, override them with --extra-vars and diagnose an unexpected value caused by YAML typing.
dsoxlab start ecrire-code-variables-base -
Collection types: lists, dicts, nested structures
Declare lists and lists of dicts in YAML, loop over them with loop_control: label, filter with when and reach nested fields.
dsoxlab start ecrire-code-types-collections -
facts and magic vars: ansible_facts, hostvars
Read system facts, use inventory_hostname, groups and hostvars, then cut the collection cost with gather_subset.
dsoxlab start ecrire-code-facts-magic-vars -
Custom facts: facts.d and ansible_local
Drop an INI custom fact then an executable script returning JSON into /etc/ansible/facts.d, and read them back through ansible_local.
dsoxlab start ecrire-code-custom-facts -
Variable precedence: the 22 levels
Stack the same variable at several levels to demonstrate which one wins, from role defaults up to --extra-vars.
dsoxlab start ecrire-code-precedence-variables -
register and set_fact: capture and create variables
Capture module output with register, reuse it in when and loop, create a runtime fact and persist it with cacheable: true.
dsoxlab start ecrire-code-register-set-fact -
Parallelism: forks, serial, throttle, strategy
Tell forks from serial, run a rolling update with serial: 1, compare the linear and free strategies and rate-limit a single task with throttle.
dsoxlab start ecrire-code-parallelisme-strategies -
async and poll: long tasks without blocking SSH
Detach a long task with async + poll: 0, collect its result via async_status, poll actively with until and diagnose an orphaned job.
dsoxlab start ecrire-code-async-poll -
Delegation: delegate_to, run_once, local_action
Redirect a task to another host, run it only once in a multi-host play and target the control node with local_action.
dsoxlab start ecrire-code-delegation -
lookups: fetch external data at runtime
Read a file, an environment variable or a command output on the control node, generate a password and tell lookup from query.
dsoxlab start ecrire-code-lookups -
Jinja2: interpolation, logic and whitespace
Interpolate variables, loop and branch inside a template, then kill stray blank lines with whitespace control.
dsoxlab start ecrire-code-jinja2-base -
Essential Jinja2 filters: default, combine, selectattr
Handle missing variables with default, work on lists, filter a list of dicts with selectattr and map, merge dicts with combine.
dsoxlab start ecrire-code-filtres-jinja-essentiels -
when conditions: operators and Jinja tests
Gate a task on a fact, combine several conditions, test whether a variable is defined and diagnose a when that matches wrongly.
dsoxlab start ecrire-code-conditions-when -
loop: iterate over lists and dicts
Loop over a list and a list of dicts, keep console output readable with loop_control: label, iterate a dict with dict2items.
dsoxlab start ecrire-code-boucles-loop -
Legacy with_* loops: migrating to loop
Recognise with_items, with_dict and with_subelements, migrate them to loop plus Jinja2 filters and automate it with ansible-lint --fix.
dsoxlab start ecrire-code-boucles-with-deprecated -
block, rescue, always: try/catch/finally
Group tasks in a block, catch the error with rescue to roll back, guarantee cleanup with always and read ansible_failed_task.
dsoxlab start ecrire-code-block-rescue-always -
failed_when and changed_when: redefine success and change
Neutralise changed on read-only commands, define changed_when from output and accept some return codes as success.
dsoxlab start ecrire-code-failed-when-changed-when -
ignore_errors: legitimate use vs anti-pattern
Measure the effect of ignore_errors on the PLAY RECAP, spot its few legitimate cases and prefer failed_when or block/rescue.
dsoxlab start ecrire-code-ignore-errors -
any_errors_fatal: stop the play on the first error
Enable any_errors_fatal on a multi-host play, compare it with the default and with max_fail_percentage, and combine it with serial.
dsoxlab start ecrire-code-any-errors-fatal -
Advanced Jinja2 filters: regex, b64, password_hash
Extract with regex_search, encode to base64, hash a password with sha512, query JSON with json_query and handle IPs and CIDRs.
dsoxlab start ecrire-code-filtres-jinja-avances -
Jinja2 tests: is defined, is mapping, is sequence
Test a variable's definition and type, match a regex with is match and is search, and combine those tests in when and in {% if %}.
dsoxlab start ecrire-code-tests-jinja -
template module: validate, backup, whitespace
Render a config from a Jinja2 template, reject invalid syntax with validate, back up the previous file and set mode, owner and group.
dsoxlab start ecrire-code-module-template -
lineinfile vs template: which module when
Arbitrate between lineinfile, blockinfile and template, combine base plus overrides and diagnose a lineinfile that stacks for lack of a regexp.
dsoxlab start ecrire-code-lineinfile-vs-template -
import vs include: static or dynamic
Choose between import_* parsed at start and include_* resolved at runtime, and observe how tags and when behave differently in each case.
dsoxlab start ecrire-code-import-include
File modules
-
copy module: transfer files and inline content
Transfer a file with src: or write inline content with content:, mastering mode, owner, backup and validate.
dsoxlab start modules-fichiers-copy -
file module: states, permissions and symlinks
Manage the state of a file or directory (directory, absent, link, hard, touch), recursive permissions and symbolic links.
dsoxlab start modules-fichiers-file -
blockinfile module: idempotent multi-line block
Insert and maintain a multi-line block in an existing file with custom markers, insertafter/insertbefore and idempotence.
dsoxlab start modules-fichiers-blockinfile -
lineinfile module: edit a line in an existing file
Add, replace by regexp or remove a line in a config file, using backrefs and syntax validation before the write.
dsoxlab start modules-fichiers-lineinfile -
replace module: substitute a pattern in a file
Substitute a regex pattern throughout a file, scope it with before/after, and preserve parts of it with capture groups.
dsoxlab start modules-fichiers-replace -
fetch module: retrieve files from managed nodes
Collect logs and configs from managed nodes to the control node, per-host tree or flat mode with inventory_hostname.
dsoxlab start modules-fichiers-fetch -
archive and unarchive modules: compress and extract
Create a tar.gz archive on the managed node and extract local, remote or already-present tarballs idempotently with creates.
dsoxlab start modules-fichiers-archive-unarchive
Package modules
-
package module: distro-agnostic installation
Install and remove packages without depending on the distro package manager, weighing state: present against state: latest.
dsoxlab start modules-paquets-package -
dnf module: enablerepo, security, exclude, autoremove
Enable a repo on the fly, patch CVEs only, exclude the kernel from a bulk upgrade and clean up orphaned dependencies.
dsoxlab start modules-paquets-dnf-options -
yum_repository module: declare an RPM repository
Declare a yum/dnf repository with gpgcheck, import its GPG key via rpm_key, and disable a repo without removing it.
dsoxlab start modules-paquets-yum-repository
Service modules
-
systemd_service module: manage systemd services
Start, enable, reload and mask services, drop a custom unit file with daemon_reload, and notify a service from a handler.
dsoxlab start modules-services-systemd -
cron module: schedule idempotent jobs
Schedule idempotent cron jobs via a user crontab or /etc/cron.d, with environment variables and clean disabling.
dsoxlab start modules-services-cron
User modules
-
user module: create, modify and remove accounts
Create accounts with home, shell and secondary groups, hash a password, force a specific UID, and remove an account with its home.
dsoxlab start modules-utilisateurs-user -
group module: manage Linux groups
Create groups with a forced GID, tell system groups from user groups, and order group creation before the users that reference it.
dsoxlab start modules-utilisateurs-group -
authorized_key module: user SSH keys
Provision public SSH keys, force an exclusive list, restrict a key with key_options, and handle several users with subelements.
dsoxlab start modules-utilisateurs-authorized-key -
sudoers module: manage sudo rights safely
Create rules under /etc/sudoers.d/ with automatic visudo validation, limit allowed commands, and handle nopassword on a group.
dsoxlab start modules-utilisateurs-sudoers
RHEL modules
-
firewalld module: manage the RHEL firewall
Allow predefined services and custom ports per zone, with the permanent + immediate trap and the firewall reload.
dsoxlab start modules-rhel-firewalld -
sysctl module: persisted kernel parameters
Change kernel parameters (ip_forward, tcp_syncookies, swappiness) with immediate effect and persistence through /etc/sysctl.d/.
dsoxlab start modules-rhel-sysctl -
selinux module: modes, booleans and contexts
Switch SELinux to enforcing, flip a boolean persistently, and set a custom context with sefcontext followed by restorecon.
dsoxlab start modules-rhel-selinux -
mount module: manage fstab and mount points
Handle the 5 mount states, mount a loop device, set noatime/nodev/nosuid options, and make a mount survive a reboot.
dsoxlab start modules-rhel-mount -
parted module: create a disk partition
Create aligned MBR or GPT partitions idempotently, set flags (lvm, boot, esp), and inspect the existing partition table.
dsoxlab start modules-rhel-parted -
filesystem module: create a filesystem
Format partitions as ext4 and xfs, pick the right fstype for the use case, and force a rebuild with force: true.
dsoxlab start modules-rhel-filesystem -
LVM: chaining lvg, lvol, filesystem and mount
Build a PV, VG and LV on a spare disk, format it, mount it through fstab, and grow it online with resizefs.
dsoxlab start modules-rhel-lvm-storage
Network modules
-
get_url module: download a file over HTTP/HTTPS
Download a file onto the managed node idempotently, check its integrity with a sha256 checksum, and authenticate the request.
dsoxlab start modules-reseau-get-url -
uri module: REST API calls
Call a REST API with GET/POST and a JSON body, accept several status_code values, and loop a healthcheck with until/retries.
dsoxlab start modules-reseau-uri
Diagnostic modules
-
stat module: inspect files and directories
Check existence, type, size, mode and checksum of a file without modifying it, to drive conditional logic.
dsoxlab start modules-diagnostic-stat -
find module: multi-file search
Search files by glob, regex, age, size and type, then chain loop and file for a targeted, idempotent cleanup.
dsoxlab start modules-diagnostic-find -
assert and fail modules: defensive validation
Validate prerequisites at the start of a play, customize fail_msg and success_msg, and fail explicitly on an error branch.
dsoxlab start modules-diagnostic-assert-fail -
wait_for and pause modules: synchronization
Wait for a TCP port to open or close, for a file or a regex to appear, and add a timed or interactive pause.
dsoxlab start modules-diagnostic-wait-for-pause
Inventories
-
Write a static inventory from scratch: groups, children and group vars
Author an Ansible static inventory by hand: declare host groups, a parent group with children, and group variables, then prove the resolved inventory with ansible-inventory and ansible -m ping.
dsoxlab start inventaires-statiques -
group_vars and host_vars: structured inventory variables
Spread inventory variables across all, group and host levels, then check the resolved value with ansible-inventory --host.
dsoxlab start inventaires-group-vars-host-vars -
Host patterns: wildcards and the :, & and ! operators
Target exactly the hosts you want with --limit and the union, intersection and exclusion operators, without touching the playbook.
dsoxlab start inventaires-patterns-hotes -
Dynamic KVM inventory with community.libvirt
Discover libvirt VMs automatically through the inventory plugin, build Jinja groups and keyed_groups, with no manual inventory.
dsoxlab start inventaires-dynamique-kvm
Roles
-
Create your first role with ansible-galaxy role init
Scaffold a webserver role, fill in tasks, defaults, handlers and meta, then call it from a playbook with roles:.
dsoxlab start roles-creer-premier-role -
Role variables: defaults/ vs vars/ and precedence
Split variables between defaults/ (overridable) and vars/ (internal), wire them into tasks and a Jinja2 template, then verify precedence.
dsoxlab start roles-variables-defaults-vars -
Role handlers and meta: notify and galaxy_info
Write several handlers (service and non-service), trigger them with notify, choose between restarted and reloaded, then complete meta/main.yml for Galaxy.
dsoxlab start roles-handlers-meta -
argument_specs: validate a role's input variables
Write meta/argument_specs.yml to type, constrain and document input variables, then watch an invalid input get rejected automatically.
dsoxlab start roles-argument-specs -
Consume a role: roles:, import_role, include_role
Call the same role three different ways and choose between static and dynamic, especially once a when: is involved.
dsoxlab start roles-consommer-role -
Role dependencies via meta/main.yml
Chain roles with dependencies:, pass them variables, control execution order and dodge the diamond trap with allow_duplicates.
dsoxlab start roles-dependencies -
RHEL system roles: converge time synchronisation with timesync
Consume a vendor role from linux-system-roles: drive chronyd on db1.lab through timesync variables, never writing chrony.conf by hand.
dsoxlab start roles-system-roles
Testing with Molecule
-
Molecule: anatomy of a test scenario
Read a molecule/default/ scenario: molecule.yml, converge.yml, verify.yml, driver, platforms, verifier, then run the full cycle.
dsoxlab start molecule-introduction -
Molecule: enrich a scenario beyond the defaults
Add prepare.yml and requirements.yml, tune instances through host_vars, define a test_sequence including idempotence and enable profile_tasks.
dsoxlab start molecule-installation-config -
Molecule: build a users role test-first
Write verify.yml and argument_specs.yml before a single task, then iterate on converge until green and refactor without breaking the tests.
dsoxlab start molecule-tdd-cycle -
Molecule: test a role across distributions
Extend the Molecule matrix to three distributions, load vars/<os_family>.yml and absorb package and path gaps with the package module.
dsoxlab start molecule-scenarios-multi-distro
Python tests and linting
-
Molecule + testinfra: Python assertions on a role
Switch the verifier to testinfra, write assertions with the host fixture, parametrize cases, and weigh it against verify.yml.
dsoxlab start tests-testinfra -
tox: test a role against several ansible-core versions
Write a tox.ini that pins one ansible-core version per environment and runs molecule test across the whole matrix in a single command.
dsoxlab start tests-tox-multiversion -
ansible-lint production profile with pre-commit
Configure .ansible-lint on the production profile plus a strict .yamllint, then wire both into pre-commit with a secret-leak hook.
dsoxlab start tests-ansible-lint-production
Continuous integration
-
GitHub Actions: CI workflow for a role
Write a lint + molecule workflow with a distro x ansible-core matrix, pip caching, least-privilege permissions and persist-credentials disabled.
dsoxlab start ci-github-actions -
GitLab CI: parallel:matrix pipeline for a role
Write a .gitlab-ci.yml with lint, test and release stages, spread the matrix with parallel:matrix and restrict Galaxy publishing to Git tags via rules:.
dsoxlab start ci-gitlab
Galaxy and publishing
-
ansible-galaxy CLI: init, install, list, build, publish
Init a role and a collection, install from Galaxy or Git, list what is present, build a tarball and publish it with an API token.
dsoxlab start galaxy-ansible-galaxy-cli -
Install roles and collections from Galaxy or Git
Write a requirements.yml mixing Galaxy roles, Git sources and collections, pin every version and vendor a role into the project for reproducible installs.
dsoxlab start galaxy-installer-roles -
Audit a Galaxy role before adopting it
Score a third-party role on six axes (maintainer, quality, security, tests), spot the anti-patterns and decide: adopt, fork or reject.
dsoxlab start galaxy-auditer-role-existant -
Version and publish a role: semver, Git tags, Galaxy
Apply semver to a role, keep a CHANGELOG.md, cut an annotated Git tag and automate Galaxy publishing from CI.
dsoxlab start galaxy-versionner-publier
Ansible Vault
-
Ansible Vault: encrypt your first secrets file
Encrypt a YAML file with ansible-vault, view it, edit it, consume it from a playbook, then rekey and decrypt it.
dsoxlab start vault-introduction -
encrypt_string vs whole-file encryption
Encrypt a single value with encrypt_string, mix it with plaintext variables via the !vault tag, and choose between inline and whole-file.
dsoxlab start vault-chiffrer-fichier-variable -
Multiple vault-ids: isolate dev, staging and prod
Encrypt each environment with a labelled vault-id, decrypt several vault-ids in a single run and lay out group_vars per environment.
dsoxlab start vault-id-multiples -
Mixed playbooks: main.yml plus vault.yml per group
Split public variables from secrets inside each group_vars, adopt the vault_* convention, and confirm Ansible merges both files transparently.
dsoxlab start vault-playbooks-mixtes -
Vault inside a role: plaintext defaults, encrypted vars
Expose public variables in defaults/main.yml pointing to vault_* values in an encrypted vars/main.yml, and override them from the playbook.
dsoxlab start vault-dans-roles -
Fetch secrets from HashiCorp Vault or OpenBao
Start a local Vault, store a secret in it, read it from Ansible with community.hashi_vault, and compare token, AppRole and JWT authentication.
dsoxlab start vault-integration-hashicorp -
Fetch secrets from Passbolt
Start a local Passbolt CE, authenticate with an OpenPGP key, read a secret from Ansible and compare the Passbolt model with HashiCorp Vault.
dsoxlab start vault-integration-passbolt
Execution environments
-
First run inside an Execution Environment
Pull an EE image with Podman, set it as the default in ansible-navigator.yml, run a playbook inside it and compare with a plain ansible-playbook run.
dsoxlab start ee-hello -
Inspect an Execution Environment and pick the right one
List an EE's contents with ansible-navigator, compare community-ansible-dev-tools, awx-ee and community-ee-minimal, then pick one per use case.
dsoxlab start ee-inspection -
Build a custom EE with ansible-builder v3
Write a v3 execution-environment.yml, pin ansible-core and dependencies, build with Podman, test the image and push it to a private registry.
dsoxlab start ee-builder-custom -
CI/CD pipeline for Execution Environments
Build an EE in CI, scan it with Trivy in blocking mode, sign it with keyless cosign and publish it, with SHA-pinned actions and least-privilege permissions.
dsoxlab start ee-ci-pipeline -
Debug a broken Execution Environment
Diagnose an EE that builds cleanly yet ships empty: forgotten schema version, missing collection or PyPI version, then fix it and verify.
dsoxlab start ee-debug
Troubleshooting
-
Verbosity levels and callback plugins
Pick the -v level that matches the symptom, enable profile_tasks and YAML output (callback_result_format), and see what a missing no_log leaks.
dsoxlab start troubleshooting-verbosite -
Interactive debugger: debugger: on_failed
Enable the debugger on failure, inspect task, task_vars and result in the REPL, patch arguments on the fly then replay the task with redo.
dsoxlab start troubleshooting-debugger -
Fix broken idempotence and tune performance
Make a shell task idempotent with creates or changed_when, measure a baseline with profile_tasks, then enable pipelining, forks and ControlPersist.
dsoxlab start troubleshooting-idempotence-perfs
Collections
-
Explore Ansible collections: FQCN and structure
List and inspect installed collections, read a galaxy.yml, walk the plugins/roles/playbooks layout and track down a module by its FQCN.
dsoxlab start collections-decouvrir -
Automation content navigator: discover a module in a collection and use it
Use ansible-navigator to find a module inside an installed collection, apply it to produce a verifiable kernel state on db1.lab, and validate an inventory with ansible-navigator inventory.
dsoxlab start collections-navigator -
requirements.yml: multi-source install with GPG signatures
Declare four sources in a requirements.yml, pin every version, check integrity with collection verify and target several Galaxy servers.
dsoxlab start collections-requirements -
Build your own collection with a custom Python module
Init a collection, fill in galaxy.yml and meta/runtime.yml, add a role and a documented Python module, then build the tarball.
dsoxlab start collections-creer-custom -
CI matrix for a collection: ansible-core x Python
Cross ansible-core and Python versions in a matrix, run ansible-test sanity and units in containers, and pin every action by SHA.
dsoxlab start collections-ci-tests -
Migrate a standalone role to a collection
Move a role and its custom module into a collection, set up plugin_routing.redirect, and check the old name still works with a warning.
dsoxlab start collections-migration-role
Advanced practices
-
Version your playbooks with Git
Initialize a Git repository for your playbooks, track and commit them, then push to a local bare remote: the exact EX294 gesture, with no forge to set up.
dsoxlab start pratiques-versionner-git -
ansible-pull: GitOps and Edge pattern
Run ansible-pull against a Git repository, schedule it with cron or a systemd timer, bootstrap it from cloud-init, then choose push or pull per use case.
dsoxlab start pratiques-ansible-pull-gitops
RHCE EX294 exam
-
RHCE EX294 mock exam: 19 tasks in 4 hours
Work through 19 timed tasks covering inventories, variables, vault, files, packages, services, roles, error handling, rolling waves, delegation, tags, scheduled jobs, custom facts and content collections, each validated by pytest.
dsoxlab start rhce-mock-ex294 -
Mock RHCE EX294 #2
A second full timed EX294 mock: the same 19 categories as mock #1, but every concrete value differs (Apache/valkey stack, different users, LVM layout, ports, SELinux boolean, cron schedule, collection), so nothing can be copied from memory. Each task is proven by pytest.
dsoxlab start rhce-mock-ex294-2
Terraform, Associate and Professional
Add this catalogue dsoxlab catalog add https://github.com/stephrobert/terraform-dsoxlab-training
Discover Terraform
-
Prove that Terraform has a memory
A beginner believes Terraform re-reads the `.tf` files and queries the infrastructure on every command, the state being an accessory cache. Take that idea apart on a purely local configuration: prove a second apply changes nothing, that drift caused outside Terraform is detected without losing the identity of the untouched resources, that data merely read is not a managed resource, and that an object nobody declared stays invisible.
dsoxlab start getting-started-terraform-overview -
Prove idempotence where the imperative script diverges
A provisioning script is provided, and it diverges as soon as you replay it: a new identifier every time, a report that piles up instead of being replaced. Reach the same result in Terraform, then establish by the plan that a second pass is a non-event, and repair an external drift without touching your code.
dsoxlab start getting-started-declarative-vs-imperative -
Prove Terraform / OpenTofu compatibility, and where it stops
"The two tools are compatible" is repeated everywhere and checked by nobody. Make a configuration portable by declaring the source and version constraint of every provider, then establish by the structured state that both binaries read the same state, resolve the same versions on two different registries, and that the lock file is exactly where portability stops.
dsoxlab start getting-started-terraform-vs-opentofu -
Pin the CLI version and lock the providers
Installing the binary proves almost nothing. Constrain the CLI version from the configuration itself, pin the three providers, make an impossible constraint refuse to run, and prove the lock file rules: wipe `.terraform/`, re-init, and the resolved versions must not move.
dsoxlab start getting-started-install-terraform -
Make fmt, validate and the outputs agree
Three faults are planted: a file outside canonical format, an orphan reference that fails `validate`, and missing outputs. Fix all three without changing what the configuration produces, then prove an expression recomputes outside the state.
dsoxlab start getting-started-cli-terraform -
Read a plan before applying it
An already applied configuration must change. Before touching anything, say which of its resources will be updated in place and which will be destroyed then recreated. The human-facing plan announces both in the same block of text: the only reliable reading is the actions field of the plan converted to JSON. Then apply exactly the plan you read, from a saved plan file.
dsoxlab start getting-started-terraform-workflow -
What Terraform manages, and what it merely reads
One word separates the two kinds of block: `resource` creates and manages, `data` reads. Prove it in the `mode` field of state, then observe the two consequences: a `destroy` does not touch what it did not create, and a data source is re-read on every plan.
dsoxlab start getting-started-providers-resources-data-sources -
Split a monolith without moving the plan
File names have no functional effect: Terraform reads every `.tf` as one document. Split a monolith into six thematic files and prove, by comparing two JSON plans, that nothing changed. Then observe which value source wins.
dsoxlab start getting-started-terraform-project-structure
First infrastructures
-
First infrastructure: the full cycle, proven
Run the Terraform cycle on a REAL resource rather than reciting it, and learn on the way that `~> 0.8` does not forbid `0.9.x`: the pessimistic operator increments the rightmost component, and the 0.9 branch rewrote the resource schema.
dsoxlab start first-infra-first-infrastructure -
Variables, locals and the real precedence order
Four rungs, checked in order: `default`, `TF_VAR_`, `terraform.tfvars`, `*.auto.tfvars`, `-var`. The decisive one is the second: a values file BEATS the environment variable, the rank almost everyone places too high.
dsoxlab start first-infra-variables-outputs -
The dependency Terraform cannot guess
Terraform builds its graph from the REFERENCES it finds in expressions. Nine times out of ten a hand-written `depends_on` signals a missing reference. This lab is about the tenth: a block that consumes a variable and references nothing, where Terraform is free to act in the wrong order.
dsoxlab start first-infra-virtual-network -
Update in place or replacement: read it in the plan
On a virtual machine, some attributes change in place and others destroy then recreate the machine. The plan says which, before the apply, provided you know where to look. Then verify the plan told the truth, by applying it.
dsoxlab start first-infra-vm-libvirt -
Produce an Ansible inventory from the state
Terraform knows what it created; Ansible must know it too. Build the bridge, and make it RELIABLE rather than merely functional: a typed variable, addresses computed by an HCL function, a serialised file, and an inventory that disappears with the fleet it describes.
dsoxlab start first-infra-ansible -
Resume after a failed apply, without redoing the work
An apply that fails halfway leaves a PARTIAL state. It is not an accident to wipe: it is the starting point of the repair. Fix the cause in the configuration, and prove the already created resources kept their identifiers.
dsoxlab start first-infra-debug-apply -
Destroying cleanly, and the four things it covers
Destroying is not one operation. Observe four that do not resemble each other: the global destroy a guard can REFUSE, the targeted destroy, the removal of a resource FROM THE CODE, and the full destroy that empties the state without deleting its file.
dsoxlab start first-infra-clean-destroy
Writing Terraform code
-
Explicit source and provider alias
Declare providers correctly: an explicit source address that resolves to registry.terraform.io/hashicorp/random, a second configuration of the same provider distinguished by an alias, and a resource wired to it with provider =. Proven by version -json and the plan JSON provider_config. Associate 5b.
dsoxlab start write-code-providers -
Read a resource's lifecycle in the plan
Build four resources ordered only by references, then prove in the plan JSON the four lifecycle operations: update in place, replace, create before destroy, and destroy. Pro objective 1c.
dsoxlab start write-code-declare-resources -
Variables typing, validation and precedence
Type variables correctly and master their traps: a map of objects with optional() defaults, a validation rule that rejects before any provider, an explicit null that falls back to the default with nullable=false, the real source precedence (auto.tfvars over TF_VAR_, -var above all), and sensitive as a display mask, not a state protection. Associate 2e plus 2f.
dsoxlab start write-code-variables -
The secret the output does not hide
Master the real output block: a type constraint (object), sensitivity propagation (an output referencing a secret must be sensitive, and sensitive is only a display mask, cleartext stays in state, -json and -raw), nonsensitive() to expose a hash deliberately, and a precondition that fails the plan. Associate 2e plus 2f.
dsoxlab start write-code-outputs -
The local that is not resolved at plan time
Centralize expressions in locals blocks: normalize with HCL functions, keep a ternary typed, generate a list with a for expression, derive from a resource attribute (known after apply), and inherit a variable's sensitivity. Pro objective 2c.
dsoxlab start write-code-locals -
When exactly does Terraform read a data source?
Build three data sources whose read timing is deliberate: one read during the plan, one deferred to the apply because the resource it depends on is changing, and one carrying an explicit depends_on that does NOT defer it. Prove each case in the plan JSON. Pro objective 2b.
dsoxlab start write-code-data-sources -
What expressions really compute
Write correct Terraform expressions: reference a managed resource with no prefix, know that == does not convert types (so 3 is not "3") while arithmetic does, respect operator precedence, and use null to omit an argument rather than an empty string. Associate 2e.
dsoxlab start write-code-expressions -
Compose values with HCL functions
Deduplicate a collection for for_each, handle out-of-range element(), lookup() fallback, ceil() rounding, template escaping and a provider-defined function. Pro objective 2c.
dsoxlab start write-code-functions -
Provider-defined functions
Use functions exposed by a provider with the provider:: syntax. Pro objectives 2c and 5a.
dsoxlab start write-code-provider-defined-functions -
The configuration that refuses absurd values
Compute values with conditional expressions, then place each guard at the right level: validation, precondition, postcondition and check block. Pro objective 2a.
dsoxlab start write-code-conditionals -
Custom conditions: precondition, postcondition and check blocks
Validate a configuration with the language features designed for it. Pro objective 2a.
dsoxlab start write-code-validation-check-preconditions -
count indexes by position, and the position lies
Choose count or for_each per resource and prove it: index a set by name with for_each, migrate a count resource to for_each with no destroy using moved blocks, keep count for interchangeable copies, and expose a conditional resource with one(). Associate objective 4b plus the Professional moved migration.
dsoxlab start write-code-count -
Add an instance without destroying the others
Migrate count to for_each with moved blocks on an already applied configuration, then add a service proving zero destruction. Pro objective 2d.
dsoxlab start write-code-for-each -
Transform a catalog with for expressions
Derive four collections from a single map of servers with for expressions: a filtered tuple, an object grouped by role with the ellipsis, a flattened two-level cross, and a filtered for_each. Avoid the splat-on-a-map trap. Pro objective 2c.
dsoxlab start write-code-for-loops -
Generate blocks, and know when not to
Generate cloudinit parts with a dynamic block filtered in for_each and named from the key, keep the fixed part literal, and hit the wall: a lifecycle meta-argument block cannot be generated by dynamic. Pro objective 2d.
dsoxlab start write-code-dynamic-blocks -
depends_on belongs only where a reference cannot go
Remove a redundant depends_on that a reference already covers, replace a hardcoded path with a reference, keep the one depends_on nothing else can express, and prove the graph in the plan JSON. Pro objective 2d.
dsoxlab start write-code-depends-on -
The lifecycle block decides the order, not you
Set create_before_destroy and watch its propagation go down to dependencies, hit the documented limit of prevent_destroy, scope ignore_changes to a single attribute, trigger a replacement from a bare value through terraform_data, and reject an invalid input at plan time. Pro objective 2d.
dsoxlab start write-code-lifecycle -
The typo that breaks nothing
Two tfvars traps: an undeclared variable in a .tfvars is only a warning, so the real variable silently stays at its default (fix the typo), and terraform.tfvars.json outranks terraform.tfvars (a distinct precedence level). Associate 3c.
dsoxlab start write-code-tfvars-files -
Version constraints and the lock file
Write correct version constraints: a literal required_version (the terraform block accepts no variable), an exact provider pin that resolves to that version, and the pessimistic ~> that allows 3.x but not 4.0. Proven by version -json and the h1 hashes of the lock file. Associate 3a.
dsoxlab start write-code-version-constraints -
The config that works but no CI accepts
Take a working but non-conforming config and make it CI-ready: pass terraform fmt, fix the orphan reference that breaks validate, rename resources to snake_case, type and describe variables and outputs, mark the token sensitive, type the number output (1.15), and write a .gitignore that excludes state but keeps the lock file. Associate 2a plus 2e.
dsoxlab start write-code-style-guide -
When sensitivity breaks for_each
A side effect of sensitive rarely taught: a sensitive value cannot be a for_each key (Invalid for_each argument), so you must iterate over a non-sensitive set. The contaminated resource attribute is flagged in sensitive_values, and a hash is exposed with nonsensitive(). Professional 2f.
dsoxlab start write-code-sensitive-data-sensitive-values -
The value that never touches the state
Declare an ephemeral value that is generated during the run but never written to the state or plan: the ephemeral block (random 3.7+), the contrast with a persisted random_password, exposing it safely at the root with ephemeralasnull(), and the two errors it triggers when leaked. Professional 2f.
dsoxlab start write-code-sensitive-data-ephemeral-values -
Write-only arguments: a secret that never lands in the state
Send a secret to the provider without ever persisting it in the Terraform state, using write-only arguments against a local AWS emulator.
dsoxlab start write-code-sensitive-data-write-only-arguments -
Read secrets from Vault
Fetch secrets from HashiCorp Vault with the vault provider and consume them without freezing them in clear text in the state. Pro objective 2f.
dsoxlab start write-code-sensitive-data-vault-secrets
Terraform state
-
Take over a secret already in service, without regenerating it
A plain `apply` would draw a new password. Attach the existing one through an `import` block, then observe that the secret sits in clear text in the state while being marked `sensitive_attributes`: masking is a display, not encryption.
dsoxlab start state-understand-state -
Migrate the state without breaking its lineage
A backend block accepts no named value. Move from an implicit local backend to a parameterised one through partial configuration and `-backend-config`, and prove the state migrated rather than being recreated: same `lineage`, both resources still managed.
dsoxlab start state-backends -
State locking, what it really blocks
Measure the exact scope of the state lock on a local backend, and state what enables it on S3.
dsoxlab start state-state-locking -
terraform state list, the address is the identity
Find the address of an instance when all you know is its real identifier, and count managed resources without being caught by a module.
dsoxlab start state-terraform-state-list -
terraform state show, and what the summary hides
Extraire du state une valeur sensible et des attributs nuls, que la sortie humaine de state show caviarde ou omet.
dsoxlab start state-terraform-state-show -
terraform state mv and the moved block, refactor without destroying
Reattach three existing objects to their new addresses, imperatively then declaratively, and prove nothing was recreated.
dsoxlab start state-terraform-state-mv -
terraform state rm and the removed block, stop managing without destroying
Take two resources out of the state without deleting the files, and learn why a removed block destroys unless you write destroy = false.
dsoxlab start state-terraform-state-rm -
The removed block: bequeath an infrastructure without destroying it
Take resources out of the state deciding for each whether the real object survives, and find where the removed block gives up. Pro objectives 1e and 4c.
dsoxlab start state-removed-block -
Restore an amputated state: pick the right backup, prove nothing was recreated
A state rm went wrong and the backup was overwritten. Three candidate backups, one restorable, compared by lineage and serial, then pushed without touching the real files.
dsoxlab start state-backup-restore-state -
Diagnose a drift and adopt an orphan resource, without losing its value
Prove a drift with a saved refresh-only plan, reconcile it, then adopt a pre-existing token with an import block, without Terraform regenerating it.
dsoxlab start state-diagnose-state
Terraform modules
-
A reusable module configures no provider of its own
Empty a child module of its provider configuration, have it declare the aliased configuration it expects, pass that configuration from the root, and instantiate the module three times with a single for_each.
dsoxlab start modules-create-modules -
Refactor a monolith into the standard module structure
Split a single .tf file into the official layout, add a nested module called by relative path, a standalone example, and prove that override.tf is the one file name with a functional effect.
dsoxlab start modules-module-structure -
A module interface is a contract, not just types
Make an object attribute optional, refuse an explicit null, reject an out-of-range value, gate an output behind a precondition, and re-export a secret without breaking the plan.
dsoxlab start modules-module-variables-outputs -
A local module is read in place, not installed
Wire two root projects onto one shared local module, and prove from modules.json which folder each call really reads: relative path versus absolute path.
dsoxlab start modules-module-local -
A registry module is downloaded, versioned, and never locked
Pin a registry module, resolve a flexible constraint, and prove from modules.json and the plan JSON which version got installed: the lock file never covers a module.
dsoxlab start modules-module-registry -
Publish and consume module versions with Git tags
Publish three versions of a shared module, then consume them from three projects: an immutable reference, a minor tag and a major tag, with no version argument in sight.
dsoxlab start modules-version-modules -
Prove a module with terraform test, mutations included
Write the .tftest.hcl suite of a module, covering its default, its options and its refusal of an invalid input: every behaviour is checked by mutating the module.
dsoxlab start modules-test-module -
Make a module composable, and prove it from the plan JSON
Strip a legacy module of its own provider configuration, invert its dependency and document it, then read the proof in provider_config and module_calls.
dsoxlab start modules-module-best-practices -
Refactor a copy-pasted project without destroying anything
Extract two copy-pasted resources into a typed module called once, and prove from the state identifiers that nothing was destroyed on the way.
dsoxlab start modules-module-anti-patterns
Environments
-
Split a monolithic configuration, and prove the plan did not move
Split an eighty-line main.tf into the official file layout, then prove by comparing two plans that nothing changed: a green validate proves nothing here.
dsoxlab start environments-organize-terraform-repo -
Two roots, two states, one shared module
Wire two root configurations onto one shared module with a partial backend, then prove by destroying dev that prod never moved.
dsoxlab start environments-separate-environments -
Which value wins, and how to prove it
Serve three environments from one configuration, restore the guard rail a stray terraform.tfvars had silenced, and prove which source wins from the plan JSON.
dsoxlab start environments-per-environment-variables -
One directory, three states that never see each other
Drive three state instances from a single configuration through terraform.workspace, then retire an inherited workspace without leaving an orphan behind.
dsoxlab start environments-workspace -
Workspaces or separate configurations, and what the split costs
Decide which parts still belong in workspaces, split the rest into two root configurations, and wire their dependency through terraform_remote_state without duplicating a value.
dsoxlab start environments-when-to-use-workspaces -
Split a monorepo into two stacks that talk to each other
Re-export a nested module output at the root, consume it from a downstream stack through terraform_remote_state, and keep the platform secret out of the shared state.
dsoxlab start environments-monorepo-vs-repo-per-stack -
Run Terraform in automation (CI/CD)
Build a non-interactive Terraform chain judged on exit codes alone, then record what a saved plan really freezes, what a lock does, and where a secret leaks.
dsoxlab start environments-terraform-in-automation
Terraform on AWS, via Floci
-
AWS provider: authentication, endpoints and default tags
Configure a pinned AWS provider so it authenticates against a local API emulator, then prove the instance really runs.
dsoxlab start aws-provider-aws-first-ec2 -
Security group: dedicated rules, for_each and a deterministic subnet
Build a security group whose rules are all dedicated resources, factor the ingress rules with for_each, and place an instance in a subnet designated by its tag.
dsoxlab start aws-sg-subnet-instance -
Compose the IAM chain, and name its two policies correctly
`aws_iam_policy_document` is a LOCAL data source: it queries nothing, it builds JSON. Compose the policy, role, instance profile and instance chain, and prove in the structured state that the trust policy and the permissions take two distinct paths to the role.
dsoxlab start aws-iam-role-policy-instance-profile -
A remote state, locked, and read by another stack
Repair a trapped backend block, make the S3 lock actually effective, and have a second configuration consume the outputs without copying a single value.
dsoxlab start aws-backend-s3-remote-state -
Read a replacement in the plan, before it happens
An ASG referencing `version = "$Latest"` never triggers an instance refresh, and a `create_before_destroy` placed on the launch template protects nothing. Read both truths in the plan converted to JSON, without ever calling AWS.
dsoxlab start aws-launch-template-autoscaling -
Import, moved and drift: the three traps a tutorial never shows
Bring an EC2 instance created outside Terraform under its control, change its logical address without the real object being recreated, then reconcile a drift by ACCEPTING reality rather than overwriting it.
dsoxlab start aws-import-moved-drift
HCP Terraform
-
The run workflow: played in two steps, then qualified
A run is a plan, then an apply of THAT plan. Reproduce it locally with saved plans, see what a stale plan and a frozen variable refuse, then qualify six described runs and put the eleven stages back in the order the documentation gives.
dsoxlab start hcp-terraform-hcp-terraform-overview -
Workspaces: one word, two meanings, two attachment strategies
A CLI workspace is one more state in the same directory; an HCP Terraform workspace is a unit of execution with its own variables, permissions and history. Repair two `cloud` blocks, attach one by name and the other by tags, and establish what `terraform validate` does not catch.
dsoxlab start hcp-terraform-hcp-workspaces -
The stream a run sends back, and the three ways to start one
What a CLI receives from a remote run is the structured stream `terraform apply -json` also produces locally. Record it, analyse it in HCL , two `change_summary` messages, only one of which says what happened , and establish what each of the three workflows allows.
dsoxlab start hcp-terraform-remote-runs -
Fifteen precedence levels, and one inversion
Among priority variable sets the broadest scope wins, whereas among normal sets it is the narrowest. Build the complete fifteen-level table, then resolve cases the tests generate and that no case-by-case answer can handle.
dsoxlab start hcp-terraform-variable-sets -
Credentials: neither in the code, nor in the state
`sensitive` hides a value from the screen, and the state holds it in clear text all the same. Take the provider's keys out of the configuration, replace a token carried in a tag with its fingerprint, and establish how dynamic credentials work.
dsoxlab start hcp-terraform-shared-credentials -
Permissions add up, they do not override
A permission set at the organization level can beat one set on the workspace, and the reverse is also true: the most permissive wins, never the most specific. Write the rule that computes six teams' effective access, and establish two scales that are not the same.
dsoxlab start hcp-terraform-projects-teams -
Policy as code: what blocks a run, and who can override it
A `hard-mandatory` is not unbypassable: the policy set setting decides, crossed with the user's permission. Qualify seven runs, establish the levels of the three frameworks, and write a rule that refuses a non-compliant plan and accepts the compliant one.
dsoxlab start hcp-terraform-policy-as-code -
The first remote run, for real (optional, needs an account)
The only lab in the catalog that needs an HCP Terraform account. Provision the platform with the `tfe` provider , project, workspace, settings, a sensitive variable , attach a configuration with a `cloud` block, and watch a run execute on HashiCorp's infrastructure.
dsoxlab start hcp-terraform-premier-run-distant
Associate certification (004)
-
The commands the exam expects, done rather than recited
Eight gestures a candidate must be able to perform: `validate`, `fmt`, the precedence cascade, `moved`, `import`, `removed` without destroying, `-replace`, and what `sensitive` really protects. Exit codes are recorded as they happen: they cannot be reconstructed afterwards.
dsoxlab start certifications-associate-essential-commands -
Associate 004: mock exam
Associate 004 mock exam, validated by pytest.
dsoxlab start certifications-associate-mock-004
Professional certification
-
Pro · Objective 1: resource lifecycle, import and drift reconciliation
Import into state an EC2 instance created outside Terraform (aws cli on Floci), then detect and reconcile a drift. Exam objective 1.
dsoxlab start certifications-professional-capstone1-resource-lifecycle -
Pro · Objective 2: dynamic configuration and troubleshooting
Data sources, HCL functions, meta-arguments (count/for_each/dynamic), complex types, sensitive data and Vault. Exam objective 2.
dsoxlab start certifications-professional-capstone2-dynamic-config -
Pro · Objective 3: collaborative workflows
Remote state (S3 backend on Floci), version constraints, workflow in automation and data sharing via terraform_remote_state. Exam objective 3.
dsoxlab start certifications-professional-capstone3-collaborative-workflows -
Pro · Objective 4: create, maintain and use modules
Create a module, consume it, refactor and version it; refactor a flat configuration into modules. Exam objective 4.
dsoxlab start certifications-professional-capstone4-modules -
Pro · Objective 5: configure and use providers
Plugin architecture, aliasing, versioning/sourcing/upgrades, authentication and provider error troubleshooting (on Floci). Exam objective 5.
dsoxlab start certifications-professional-capstone5-providers -
Pro · Objective 6: HCP Terraform, where the sub-objectives cross
Objective 6 is assessed by multiple choice, and needs no account. Six situations that each cross two sub-objectives, a `cloud` block to write, and a secret that must not reach the state. Six situations, six different outcomes: no constant answer passes.
dsoxlab start certifications-professional-capstone6-hcp -
Pro · Integrative mock exam: the six objectives in one sitting
A rehearsal, not a lesson: six tasks, one per objective, to be played in one go once the six capstones are done. Drift reconciliation, dynamic configuration, two states that talk, a module that recreates nothing, two configurations of one provider, and a twelve-question HCP paper scored per sub-objective.
dsoxlab start certifications-professional-mock-pro
Kubernetes, CKA, CKAD and CKS
Add this catalogue dsoxlab catalog add https://github.com/stephrobert/kubernetes-dsoxlab-training
CKA, Certified Kubernetes Administrator
-
Place a static Pod on a worker, without going through the API
Run a Pod that the worker's kubelet manages on its own, from a manifest dropped on the node, and see it appear in the API under its mirror name. The file must sit where the kubelet's own configuration says, and the worker's runtime must really be running the container.
dsoxlab start cka-static-pod -
An agent on every node, including the control plane
Deploy a DaemonSet that places an agent on every node of the cluster, including the control plane, protected by its taint. The tests count one Pod per node, check that the taint is still there and that the agent runs on it anyway, and read its logs to prove that it is doing its job.
dsoxlab start cka-daemonset-all-nodes -
Give an application an identity: ServiceAccount, Role, RoleBinding
An application refuses to start because its ServiceAccount does not exist. Create it, grant it the right to read the Pods of its namespace and nothing else, then prove from inside the Pod, with its own token, that listing goes through and that deleting, reading Secrets or looking elsewhere are denied.
dsoxlab start cka-rbac-serviceaccount -
Reserve a node: taint, toleration and nodeSelector
Reserve the worker for production with a taint and a label, then place a Pod that must go there, toleration and nodeSelector, and a Pod that must not. The tests read the node, the actual placement of each Pod and the declared mechanisms: a Pod pinned with nodeName bypasses the taint and does not pass.
dsoxlab start cka-taints-tolerations-placement -
Placing with nodeAffinity: required constraint and preference
Place a Deployment with a required node affinity on a label that accepts several values, add a weighted preference to it, then unblock a Pod that is waiting for a node which does not exist yet, by setting the label it demands. The tests read the node labels, the declared affinities and the actual node of every Pod.
dsoxlab start cka-node-affinity -
Isolate the database: only the backend gets in
Write the NetworkPolicy that lets nothing into the database but the backend of its own namespace, on its port. The tests attempt the connections: the one that must go through, the frontend one that must be blocked, the one from a Pod with the right label but in another namespace, and they check that the database can still reach out.
dsoxlab start cka-networkpolicy-isolate-db -
Route two applications on a single host, and prove each gets its own
Two applications, one hostname, and no rule saying which is which. Route by path, and prove it the only way that counts: each path answers with its own application's name, and an undeclared path answers with neither.
dsoxlab start cka-ingress-path-routing -
Route with the Gateway API, and watch the Gateway report itself programmed
Same two applications, same single hostname, and the successor to Ingress. Declare a Gateway, attach a route to it, and prove the routing: each path answers with its own application's name, an undeclared path answers with neither.
dsoxlab start cka-gateway-api-httproute -
A persistent volume: PersistentVolume, PersistentVolumeClaim and a Pod that writes
On a cluster with no dynamic provisioning, create a PersistentVolume on a node's disk, claim it with a PersistentVolumeClaim, mount it in a Pod that writes to it. The tests read the volume, the binding, the mount, the file inside the Pod, then the same file on the node's disk: that is where persistence is proven.
dsoxlab start cka-pv-pvc-storageclass -
Get a volume no administrator created, and follow what becomes of it
A claim stuck in Pending because nobody prepared a volume by hand. Let the cluster provision it on demand, then observe what the class decides when the claim disappears: the volume goes with it.
dsoxlab start cka-storageclass-provisionnement-dynamique -
Roll back a stuck rollout, then ship the right version
An update went out with a wrong image name and the rollout is stuck. Go back to the revision that worked through the Deployment history, then ship the correct image with a change cause. The tests read the ReplicaSets and their revision numbers: they tell the story of what happened, and a Deployment recreated from scratch tells no story at all.
dsoxlab start cka-deployment-rollout-rollback -
Drain a worker for maintenance, without cutting the service
Protect an application with a PodDisruptionBudget, take the worker out of scheduling, evict it while respecting that budget and the DaemonSets, then put it back in service and record the operation. The tests prove that the Pods really were recreated elsewhere, that the node came back, and that the CNI DaemonSet did not move.
dsoxlab start cka-node-drain-cordon -
Scale out automatically with a HorizontalPodAutoscaler
Put an HPA on a Deployment, generate load, watch the replica count go up, then cut the load. The tests read the HPA, its current metrics, and the rescale event the controller emitted: an HPA that has never rescaled is not a validated HPA.
dsoxlab start cka-hpa-autoscaling -
Cap a namespace without blocking those who forget to declare themselves
A namespace with no ceiling and no defaults: one team can take the whole cluster, and a Pod with no requests is scheduled blind. Set both, and prove each: a Pod asking too much is refused, a Pod asking nothing is accepted and completed.
dsoxlab start cka-resourcequota-limitrange -
Get a Pod out of ImagePullBackOff
A Pod does not start because its image will not download. Read the runtime's exact message in the events, fix the image reference, and prove that the server answers.
dsoxlab start cka-troubleshoot-imagepullbackoff -
Get a Deployment out of CrashLoopBackOff
The Pods of a Deployment have been restarting in a loop since the last release. Read what the process said before it died, work out what it is missing, fix the Deployment, and prove the application serves again.
dsoxlab start cka-troubleshoot-crashloopbackoff -
Get inside a container with no shell using kubectl debug
A Pod whose image contains no shell offers nothing to kubectl exec. Attach an ephemeral container to it that shares its processes, reach the node's filesystem through a debug Pod, and leave proof of it.
dsoxlab start cka-kubectl-debug -
Restore the cluster's DNS resolution
No Pod resolves a service name any more. Find out why the cluster DNS has stopped answering, put it back in service, and prove that a client Pod resolves and reaches a Service by its name again.
dsoxlab start cka-troubleshoot-dns -
Restore traffic to a Service
A Service no longer serves its Pods: wrong selector, wrong port, and a network policy that closes everything. Set the Service straight, reopen exactly what is needed without removing the security policy, and prove that a client reaches the Service by its name.
dsoxlab start cka-troubleshoot-networking -
Bring a NotReady node back into the cluster
A worker has gone NotReady, and the application reserved for it is degraded. Find out on the node why it no longer talks to the control plane, put its agent back in service for good, and prove that the application is back.
dsoxlab start cka-troubleshoot-node-notready -
Repair a kubelet that refuses to start
A worker's kubelet stops as soon as it is launched, and the node is NotReady. Read in the journal what it holds against its configuration, fix the file without breaking anything else, and prove that the node and its application are back.
dsoxlab start cka-troubleshoot-kubelet -
Bring the API server back into service
kubectl no longer answers: the control plane's API server exits with an error at startup. With no API, diagnose on the node, in the containers and in the kubelet journal, fix the static manifest, and prove the API answers without having weakened its authorization.
dsoxlab start cka-troubleshoot-apiserver -
Back up etcd, then restore the cluster from a snapshot
A namespace has disappeared. Take a fresh backup of the current state first, then restore the cluster from yesterday evening's snapshot, without stopping the wrong component and without leaving the API server on a stale cache. The tests prove that etcd runs on a data directory produced during the lab, that the objects come back with their original UID, and that what was written after the backup is gone.
dsoxlab start cka-etcd-backup-restore -
Upgrade a cluster one minor version, without interrupting what runs on it
A cluster one minor version behind, an application that must keep serving, and the upgrade to run: the control plane first, then the node, each with its own command. The tests read the versions and check nothing was left drained.
dsoxlab start cka-kubeadm-upgrade -
Capstone: bring the portal back, with nobody left to ask
A namespace handed over by a team that is gone, a portal that answers nothing, and no ticket saying why. Three independent faults to find, two requirements that were never met, and a single measure of success: the portal answers on every node of the cluster.
dsoxlab start cka-capstone-portail
CKAD, Certified Kubernetes Application Developer
-
A two-container Pod, with budgets, labels and an annotation
Write by hand a Pod with two containers, each with its own requests and limits, with labels and an annotation, and prove from inside each container that the memory limit is the one the kernel enforces.
dsoxlab start ckad-pod-resources-labels -
Inject configuration and secrets into a Pod
Give an application its configuration through environment variables and through a mounted file, and its credentials through a Secret, without ever writing a password in the Pod manifest. Prove, from inside the container, that everything arrived.
dsoxlab start ckad-configmap-secret-injection -
Take a password out of a manifest, without the application noticing
A password sits in plain sight inside a Deployment manifest, which anyone who can read the manifest can read too. Move it into a Secret, inject it both as an environment variable and as a mounted file, and keep the application running.
dsoxlab start ckad-secret-injection-protection -
Three probes on one Pod: startup, liveness, readiness
Fit an application with all three probes, with settings that make sense: a slow start tolerated, liveness watched, traffic that only arrives once the Pod is ready. Prove the probes act: the Pod is Ready only because they answer.
dsoxlab start ckad-probes-all-types -
Wait for a dependency with an init container
Keep an application from starting before the Service it depends on answers, with an init container that waits. Watch the Pod held in Init, put the dependency in place, and see the application start on its own.
dsoxlab start ckad-init-container -
A native sidecar that tails the application logs
Have a second container read the logs an application writes to a file, with a native sidecar, declared as an init container with restartPolicy Always, and a shared volume. Prove that the sidecar really does pass the lines on.
dsoxlab start ckad-multi-container-sidecar -
Let one container read what another writes, and nothing else
Two containers in one Pod, one writing and one reading, and nothing shared between them. Give them a volume whose lifetime is the Pod's, and prove it both ways: what is written inside the volume crosses, what is written beside it does not.
dsoxlab start ckad-volumes-partage-entre-conteneurs -
Expose a Deployment through a ClusterIP Service
Deploy three replicas of a server and expose them through an internal Service. Prove from a client that the Service answers under its name, and that it really spreads the requests across the three Pods.
dsoxlab start ckad-expose-service -
Harden a Pod with a securityContext
Run a web server with no privilege: non-root user, no escalation, read-only root filesystem, every capability dropped. And still give it somewhere to write where it needs to, otherwise it will not start. Prove, from the inside, that the confinement holds and that the application serves.
dsoxlab start ckad-security-context-hardened -
Grant read-only access to Pods with RBAC
Let a user read the Pods of a namespace and their logs, and nothing more: no creating, no deleting, no looking into the other namespaces. Prove both sides with kubectl auth can-i, what is allowed and what stays denied.
dsoxlab start ckad-rbac-role-rolebinding -
Partition three tiers with ingress and egress NetworkPolicy
Frontend, backend, database: allow only the intended flows, in both directions, DNS included, and forbid everything else. Prove every rule with a real connection, the one that goes through and the one that is blocked.
dsoxlab start ckad-networkpolicy-ingress-egress -
Tune a rolling update: maxSurge and maxUnavailable
Constrain the way a Deployment replaces its Pods, never more than two extra ones nor more than one unavailable, then trigger an image update and prove it went all the way through: old revision down to zero, new one complete.
dsoxlab start ckad-rolling-update-strategy -
Switch traffic from one version to the other: blue-green
Run two versions of an application side by side, then switch all the traffic from one to the other by changing a Service selector. Prove the switch from a client: every request reaches the new version, none the old one.
dsoxlab start ckad-blue-green-deployment -
One Kustomize base and two overlays, dev and prod
Describe an application only once, in a Kustomize base, and deploy it into two namespaces with overlays that change the replica count, prefix the names and add an environment label. Prove that both environments are running and look alike.
dsoxlab start ckad-kustomize-overlays -
Install, upgrade and roll back with Helm 4
Deploy a chart with Helm, upgrade it with new values, then go back to the first revision. Prove through the release history and the state of the Deployment that the three operations took place, in that order.
dsoxlab start ckad-helm-install-upgrade -
A Job with parallel completions, and a CronJob
Run a workload four times, two at a time, with a Job, and prove that the runs really did overlap. Then schedule a cleanup every five minutes with a CronJob that keeps a bounded history.
dsoxlab start ckad-job-cronjob -
Resize a Pod in place, without restarting it
Raise the CPU and the memory of a running Pod, without recreating it and without restarting its container, through the resize subresource. Prove that the kernel applies the new limit and that the container stayed the same.
dsoxlab start ckad-in-place-pod-vertical-scaling -
A Pod blocked by a ConfigMap that does not exist
A Pod does not start and says nothing in its logs, because it has no container yet: its events are the ones that talk. Read the cause, create the missing resource with the expected content, and prove that the application serves.
dsoxlab start ckad-troubleshoot-missing-configmap -
Three Pods in CrashLoopBackOff, three causes
Three Pods restart in a loop for three different reasons: a command that does not exist, a missing environment variable, a memory limit set too low. Read for each one what kills it, fix it, and prove that all three hold.
dsoxlab start ckad-troubleshoot-crashloop -
Capstone: ship the shop, from the specification alone
A full delivery, given as a specification rather than a walkthrough. Six requirements to satisfy in one namespace: configuration, secret, probes, identity, exposure and isolation. Nothing says which object to create, and the last test checks the only thing that matters: a frontend Pod reaches the shop, and a Pod that is not one does not.
dsoxlab start ckad-capstone-boutique
CKS, Certified Kubernetes Security Specialist
-
Confine a Pod with an AppArmor profile
Load an AppArmor profile on the node, apply it to a container through the securityContext field, and prove that the confinement holds by watching a write the profile forbids fail.
dsoxlab start cks-apparmor-confiner-un-pod -
Deny a system call to a container, and prove it from the inside
A container that may call anything the kernel offers. Write a seccomp profile that refuses one family of system calls, apply it, and prove the confinement holds: the forbidden call fails from inside, and everything else still works.
dsoxlab start cks-seccomp-profile -
Reject a privileged Pod at admission, with Pod Security Admission
A namespace that accepts anything, including a Pod that shares the host's PID namespace and runs as root. Turn on the restricted standard so the cluster refuses it at admission, and prove the refusal without creating anything: a server-side dry run goes through admission and writes nothing.
dsoxlab start cks-pod-security-admission -
Take over a privileged Pod in production, without stopping its work
A Pod runs with the host's process namespace, as root, privileged, from a floating tag. Rebuild it without any of that, and prove the difference where it is visible: from inside, the container no longer sees the host.
dsoxlab start cks-secure-existing-pod -
Make a container immutable without bringing it down
A running Deployment can still be written to from the inside. Make its root filesystem read-only, drop every capability, forbid escalation, and keep the application serving: nginx needs a few writable paths, and finding them is the exercise.
dsoxlab start cks-security-context-immutable -
Isolate a Pod from the host kernel, and prove it by reading its version
The node offers a second container runtime that runs an application kernel of its own. Put a Pod inside it, and prove the isolation the only way that cannot be faked: from inside, the kernel version is no longer the node's.
dsoxlab start cks-runtime-sandbox-gvisor -
Pin an image by digest, and prove the tag is not enough
A Deployment that trusts a mutable tag. Pin it to the immutable digest of the image it actually runs, and prove the pin holds: the declared digest must match what the runtime resolved, not just look like one.
dsoxlab start cks-image-pinned-digest -
Have the cluster itself reject an unpinned image, with no webhook
A namespace accepts any image, tag and all. Make the API server refuse the ones that are not pinned by digest, with a policy it evaluates itself: no webhook, no controller, nothing to keep running.
dsoxlab start cks-validating-admission-policy -
Replace an image riddled with flaws, and prove it with a second scan
A Deployment runs an image three years old. Scan it, pick a replacement, and prove the choice: the test scans both and demands strictly fewer critical findings than the original, which no fixed threshold could measure honestly.
dsoxlab start cks-image-scanning-trivy -
Sign an image, and prove the signature by having another one refused
A local registry holds two images, neither signed. Sign one with cosign, publish the public key, and prove the chain works: the same key must accept the signed image and refuse the other. A verification that accepts everything proves nothing.
dsoxlab start cks-cosign-verify-image -
Fix a Dockerfile static analysis refuses, without changing the application
A Dockerfile that builds and runs, and that static analysis rejects on five counts. Fix them all without changing what the image does, and prove it by running the analysis again: the five findings must be gone by their identifiers, not by a count that a new rule would break.
dsoxlab start cks-dockerfile-static-analysis -
Take cluster-admin away from a service account, without stopping its work
A ServiceAccount holds cluster-admin because it was quicker. Take that power back and give it exactly what its application needs, no more. The proof is not the manifest: it is what the API server answers when that account asks.
dsoxlab start cks-rbac-least-privilege -
Close the API server profiler, without closing the API
The API server exposes its Go profiler to anyone who can reach it, and a kubeadm cluster leaves it on. Close it and raise the TLS floor, then prove both halves: the profiler answers 404, and the cluster still works.
dsoxlab start cks-api-server-hardening -
Record who reads Secrets, and only the metadata of everything else
The cluster keeps no trace of who reads what. Give the API server an audit policy with two levels, full bodies for Secrets and metadata for everything else, and prove it works by reading the log the cluster has just written.
dsoxlab start cks-audit-log-policy -
Deny everything, then reopen the strict minimum, DNS included
A namespace where everything talks to everything. Close it completely in both directions, then reopen exactly two things: the one flow the application needs, and name resolution, which a default-deny egress breaks in a way nothing warns you about.
dsoxlab start cks-networkpolicy-default-deny -
Require mTLS in a mesh, and prove it with a client left outside
A service mesh accepts plain traffic from anyone, inside the mesh or out. Require mutual TLS, and prove it the only way that counts: a Pod with a sidecar still reaches the service, a Pod without one no longer does.
dsoxlab start cks-istio-mtls-lockdown -
Serve a site over HTTPS with its own certificate, not the controller's
The site already answers over HTTPS, which is exactly the trap: the Ingress controller serves its own default certificate to anyone who asks. Terminate TLS with a certificate that actually names the host.
dsoxlab start cks-ingress-tls -
Bring down a CIS audit count, and prove it with a second audit
kube-bench audits the control plane against the CIS benchmark and fails ten checks on a stock kubeadm cluster. Fix the three that share one cause, then prove it the only honest way: run the audit again and count.
dsoxlab start cks-cis-benchmark-remediate -
Capstone: open an enclave for a team you do not trust
An outside team needs room in your cluster. Give them one that stays safe even if they are not: the cluster itself must refuse what they should not deploy, their identity must be able to do almost nothing, and nothing outside the enclave may reach what runs inside it.
dsoxlab start cks-capstone-enclave
GitHub Actions
Add this catalogue dsoxlab catalog add https://github.com/stephrobert/github-actions-training
Writing your first workflow
-
First workflow: the tests run on every push, and a broken test turns the pipeline red
A small Python library with nine tests that nobody runs before merging. Write the workflow that runs them on every push and pull request, with minimal permissions and pinned actions, and prove it by breaking a test.
dsoxlab start fondations-premier-workflow
No lab matches this search.
How to play a lab
The labs run with dsoxlab, a CLI that installs the catalogue, prepares the environment, gives you the brief and then runs the validation tests. Three commands are enough to start:
dsoxlab catalog add https://github.com/stephrobert/linux-dsoxlab-training
dsoxlab doctor
dsoxlab start l1-first-terminal 218 of the 352 labs provision real
virtual machines: no container will prove that you can
repair a systemd service or write an SELinux
rule. The rest only need a shell. The label appears on every row of the
catalogue, and dsoxlab doctor reports what your machine is
missing before the first run.
153 labs carry the attested mark: their repository holds a record where each lab was replayed end to end and scored both ways, zero before the work and one hundred after. The others run too, but their attestation is still to produce, and this page says so rather than making the same promise everywhere.
Install dsoxlab and understand a lab Size your machine Every command The English documentation