{"id":3663,"date":"2025-04-17T11:27:19","date_gmt":"2025-04-17T11:27:19","guid":{"rendered":"https:\/\/www.it-react.com\/?p=3663"},"modified":"2025-04-19T22:49:01","modified_gmt":"2025-04-19T22:49:01","slug":"secure-and-centralized-ubuntu-patching-with-ansible","status":"publish","type":"post","link":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/","title":{"rendered":"Secure and Centralized Ubuntu Patching with Ansible"},"content":{"rendered":"\n<p>Let\u2019s be honest \u2014 keeping a fleet of Ubuntu servers updated isn\u2019t the most glamorous job, especially when they\u2019re tucked away behind firewalls with no internet access. But what if we could turn this dusty chore into a clean, elegant, and even satisfying little automation adventure?<\/p>\n\n\n\n<p>That\u2019s exactly what we did.<\/p>\n\n\n\n<p>This was actually my first real project using<strong> <\/strong>Ansible, and it turned out to be a fantastic way to get hands-on experience and discover how powerful (and fun!) Ansible can be. From generating SSH keys to automating patch checks, it became a perfect playground for learning while building something genuinely useful.<\/p>\n\n\n\n<p>Armed with a central Ubuntu APT mirror and the magic of Ansible, we built a secure and manual-friendly patching system that makes updates feel more like pushing buttons than fighting fires. Whether you\u2019re a sysadmin who loves control or just someone who enjoys a clean playbook, this setup is built for you.<\/p>\n\n\n\n<p>In this post, I\u2019ll walk you through everything \u2014 from SSH keys to role-based task execution \u2014 and show you how to bring order, transparency, and even a little joy to your patching process.<\/p>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69e753c48f485&quot;}\" data-wp-interactive=\"core\/image\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"895\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on-async--click=\"actions.showLightbox\" data-wp-on-async--load=\"callbacks.setButtonStyles\" data-wp-on-async-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/Ansible.drawio6-1024x895.png\" alt=\"\" class=\"wp-image-3751\" srcset=\"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/Ansible.drawio6-1024x895.png 1024w, https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/Ansible.drawio6-300x262.png 300w, https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/Ansible.drawio6-768x671.png 768w, https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/Ansible.drawio6-1536x1342.png 1536w, https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/Ansible.drawio6-2048x1790.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on-async--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n\n\n\n<p>As shown in the diagram above, we have a central datacenter where our APT mirror and Ansible control node is located. From there, we securely check and manage all Ubuntu servers deployed in our Alpha and Beta datacenters.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step One: \ud83d\udd11<\/strong> <strong>SSH Key Setup for Ansible Access<\/strong><\/h2>\n\n\n\n<p>To allow the Ansible control node to connect to each Ubuntu client without password prompts, we first generate an SSH key pair on the node server:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#ssh-keygen -t ed25519 -C \"ansible-user\"<\/code><\/pre>\n\n\n\n<p>Then, copy the public key to each target host (if you have more keys, specify which key to use with <code>-i<\/code> if needed). User &#8220;ansibleadmin&#8221; should be existent on each target server.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#ssh-copy-id -i ~\/.ssh\/id_ed25519.pub ansibleadmin@&lt;host&gt;<\/code><\/pre>\n\n\n\n<p>This ensures passwordless login using the <em><strong>ansibleadmin<\/strong><\/em> user. We can also test this using command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#ssh -i ~\/.ssh\/id_ed25519.pub ansibleadmin@&lt;host&gt;<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step Two: \ud83d\udce6 Installing Ansible on the Control Node<\/strong><\/h2>\n\n\n\n<p>Ansible needs to be installed only on the control machine. On an Ubuntu system, it can be installed using the system package manager:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#sudo apt update\n#sudo apt install ansible -y<\/code><\/pre>\n\n\n\n<p>Once installed, you can verify the version with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#ansible --version<\/code><\/pre>\n\n\n\n<p>Now the control node is ready to manage remote systems using Ansible.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step Three: \ud83d\udcc1 Ansible Directory, Inventory and Configuration Files<\/strong><\/h2>\n\n\n\n<p>For our project, we started by creating a dedicated directory named <strong><em>security-patching<\/em><\/strong> under our home user folder. This became our workspace for organizing everything related to Ansible configuration and automation.<\/p>\n\n\n\n<p>At the heart of this setup are two simple but powerful files: the inventory and the configuration. These define where your servers are, how to connect to them, and how Ansible behaves overall. Here&#8217;s what they do:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em><strong>ansible.cfg<\/strong><\/em>: This optional configuration file customizes Ansible\u2019s behavior. It can set default inventory location, vault password file, privilege escalation method, SSH options, and more. <\/li>\n\n\n\n<li><strong><em>hosts.ini<\/em><\/strong>: This file defines the list of managed hosts. It groups systems logically, so you can target them by zone, datacenter, or any other label. It&#8217;s essential for Ansible to know where to connect.<\/li>\n<\/ul>\n\n\n\n<p><strong>Ansible Configuration<\/strong> <strong>&#8211; ansible.cfg<\/strong><br>Here is my ansible.cfg file that also include comments for every config line. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;defaults]\n# Path to the inventory file\ninventory = hosts.ini\n# Default SSH user to connect as                       \nremote_user = ansibleadmin\n# Private key used for authentication                 \nprivate_key_file = ~\/.ssh\/id_ed25519\n# File that stores the Ansible Vault password      \nvault_password_file = .vault_pass.txt\n# Where Ansible looks for roles      \nroles_path = roles\n# Where to log Ansible output                         \nlog_path = logs\/ansible.log\n# Auto-select Python interpreter on target hosts                \ninterpreter_python = auto_silent           \n<\/code><\/pre>\n\n\n\n<p><strong>Ansible Inventory<\/strong> <strong>&#8211; hosts.ini<\/strong><br>We organized our hosts into logical groups based on datacenter zones. Here&#8217;s the file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;alpha-dc]\nubuntu-file-1.1 ansible_host=192.168.10.101\nubuntu-file-1.2 ansible_host=192.168.10.102 \nubuntu-db-1.1   ansible_host=192.168.10.103\nubuntu-db-1.2   ansible_host=192.168.10.104\n\n&#91;beta-dc]\nubuntu-file-2.1 ansible_host=192.168.20.101\nubuntu-file-2.2 ansible_host=192.168.20.102\nubuntu-db-2.1   ansible_host=192.168.20.103\nubuntu-db-2.2   ansible_host=192.168.20.104\n\n&#91;ubuntu_servers:children]\nalpha-dc\nbeta-dc<\/code><\/pre>\n\n\n\n<p>This structure lets us run tasks per group, per environment, or across all Ubuntu servers using <code><strong>--limit<\/strong><\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step Four: \ud83e\uddea<\/strong> <strong>First Test &#8211; The Ping Module<\/strong><\/h2>\n\n\n\n<p>We verified SSH connectivity using Ansible\u2019s ping module:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#ansible -i hosts.ini ubuntu_servers -m ping<\/code><\/pre>\n\n\n\n<p>Each host should return pong, confirming Ansible can connect over SSH.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step Five: \ud83d\udd10 Using sudo and Vault for Elevated Commands<\/strong><\/h2>\n\n\n\n<p>When testing modules that require <strong><em>sudo<\/em><\/strong> (like <strong><em>apt<\/em><\/strong>), we initially hit the sudo password prompt. To avoid re-entering the password each time, we encrypted per-host sudo passwords using <strong>Ansible Vault<\/strong>.<\/p>\n\n\n\n<p>Here\u2019s how we generated the encrypted files (Please write it down and keep your vault password safe):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#ansible-vault create host_vars\/&lt;hostname&gt;\/vault.yml<\/code><\/pre>\n\n\n\n<p>Inside each file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ansible_become_password: \"your_sudo_password\"<\/code><\/pre>\n\n\n\n<p>To simplify this process, we used a Bash script (<strong>generate-vaults.sh<\/strong>) to create vaults for all hosts at once. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step Six: \ud83d\udee0\ufe0f Creating Roles and Tasks<\/strong><\/h2>\n\n\n\n<p>After identifying the core actions we needed \u2014 checking and installing updates, handling reboots, and more \u2014 we created a set of dedicated Ansible tasks to automate them. We structured the Ansible project into reusable roles. Each update scenario is handled by a separate task file. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>roles\/patching\/tasks\/\n\u251c\u2500\u2500 check_security.yml       # dry-run security updates\n\u251c\u2500\u2500 check_full.yml           # dry-run full updates\n\u251c\u2500\u2500 upgrade_security.yml     # install security updates\n\u251c\u2500\u2500 upgrade_full.yml         # full system upgrade\n\u251c\u2500\u2500 check_reboot.yml         # check if reboot needed\n\u251c\u2500\u2500 reboot_if_needed.yml     # reboot only if required<\/code><\/pre>\n\n\n\n<p>Our main playbook file (<strong>security-updates.yml<\/strong>) includes all of these and uses tags to selectively run what we need. Here a short preview :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>---\n- name: Run Ubuntu update operations\n  hosts: ubuntu_servers\n  become: yes\n  tasks:\n    - name: Include security dry-run task\n      include_tasks: ..\/roles\/patching\/tasks\/check_security.yml\n      tags: check_security\n\n    - name: Include full upgrade dry-run task\n      include_tasks: ..\/roles\/patching\/tasks\/check_full.yml\n      tags: check_full\n<\/code><\/pre>\n\n\n\n<p>\ud83d\udc49 Full playbook and task files available here: \ud83d\udd17 <a class=\"effect1\" href=\"https:\/\/github.com\/ioanpenu\/security-patching\">GitHub Repo: security-patching<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step Seven: \ud83d\udcc1 Project Directory Structure<\/strong><\/h2>\n\n\n\n<p>Now that we created all the files, here&#8217;s a simplified look at our Ansible project layout:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>security-patching\/\n\u251c\u2500\u2500 ansible.cfg\n\u251c\u2500\u2500 hosts.ini\n\u251c\u2500\u2500 playbooks\/\n\u2502   \u2514\u2500\u2500 security-updates.yml\n\u251c\u2500\u2500 roles\/\n\u2502   \u2514\u2500\u2500 patching\/\n\u2502       \u2514\u2500\u2500 tasks\/\n\u2502           \u251c\u2500\u2500 check_security.yml\n\u2502           \u251c\u2500\u2500 check_full.yml\n\u2502           \u251c\u2500\u2500 upgrade_security.yml\n\u2502           \u251c\u2500\u2500 upgrade_full.yml\n\u2502           \u251c\u2500\u2500 check_reboot.yml\n\u2502           \u2514\u2500\u2500 reboot_if_needed.yml\n\u251c\u2500\u2500 host_vars\/\n\u2502   \u2514\u2500\u2500 &lt;hostname&gt;\/\n\u2502       \u2514\u2500\u2500 vault.yml\n\u2514\u2500\u2500 .vault_pass.txt<\/code><\/pre>\n\n\n\n<p>This structure keeps everything modular, readable, and scalable \u2014 making it easy to maintain as your environment grows.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step Eight: \u25b6\ufe0f Test Application &#8211; Running Commands<\/strong><\/h2>\n\n\n\n<p>Our playbook is structured to be executed with specific tasks in mind. Running it without specifying tasks doesn&#8217;t align with its intended use and may not yield meaningful results. By focusing on particular tasks, we ensure that each execution is purposeful and targets the desired operations.\u200b<\/p>\n\n\n\n<p>With that in mind, Ansible provides flexibility to target specific groups within your inventory, allowing for precise control over task execution. For instance, you can run a particular task on a specific group by using the <code>--limit<\/code> flag in conjunction with tags:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ansible-playbook -i hosts.ini playbooks\/security-updates.yml --tags check_security --limit alpha-dc --vault-password-file .vault_pass.txt<\/code><\/pre>\n\n\n\n<p>This command will execute the tasks tagged with <strong><em>check_security<\/em><\/strong> only on the hosts within the alpha-dc group. Such granularity is invaluable when managing diverse environments with varying requirements<\/p>\n\n\n\n<p>If you\u2019re not comfortable storing your vault password in a file, you can prompt for it interactively:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ansible-playbook -i hosts.ini playbooks\/security-updates.yml --tags check_security --limit zone_alpha --ask-vault-pass<\/code><\/pre>\n\n\n\n<p>Before we wrap up, it&#8217;s worth noting that this project was just a small experiment I used to get started with Ansible. It&#8217;s a basic example that lays the groundwork for more complex automation tasks. There&#8217;s ample room to enhance this setup with additional functions and features as your familiarity with Ansible grows.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Conclusion<\/strong><\/h2>\n\n\n\n<p>This setup allowed us to bring <strong>secure automation<\/strong> to isolated environments \u2014 where visibility and control matter more than ever. Whether you&#8217;re maintaining a handful of machines or managing a growing infrastructure, this framework gives you the power to patch confidently and intentionally \u2014 no surprises, no stress.<\/p>\n\n\n\n<p>If you&#8217;d like to explore or reuse the actual playbooks, roles, and helper scripts we used, you can find the complete project on GitHub:<\/p>\n\n\n\n<p>\ud83d\udc49 Full playbook and task files available here: \ud83d\udd17 <a class=\"effect1\" href=\"https:\/\/github.com\/ioanpenu\/security-patching\">GitHub Repo: security-patching<\/a><\/p>\n\n\n\n<p>Thanks for following along \u2014 and happy patching! \u2699\ufe0f\ud83d\ude80<\/p>\n\n\n\n<p>And hey \u2014 patching doesn&#8217;t always have to feel like a chore. With a bit of YAML magic and the right setup, it can actually be&#8230; dare we say&#8230; fun? \ud83d\ude04<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\ud83d\udcac <strong>If you found this post helpful, here&#8217;s one more tip:<\/strong><br>Protect your browsing like you protect your data. I use <strong>NordVPN<\/strong> and genuinely recommend it.<br><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><strong>Get 73% off NordVPN&#8217;s 2-year plan + 3 extra months \/\/ From <del>\u20ac11.59<\/del> \u20ac3.09\/month<\/strong><\/mark><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/go.nordvpn.net\/aff_c?offer_id=15&amp;aff_id=119651&amp;url_id=902\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"205\" src=\"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/generic-banners-protect-digital-life-1500x300-1-1024x205.png\" alt=\"\" class=\"wp-image-3741\" srcset=\"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/generic-banners-protect-digital-life-1500x300-1-1024x205.png 1024w, https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/generic-banners-protect-digital-life-1500x300-1-300x60.png 300w, https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/generic-banners-protect-digital-life-1500x300-1-768x154.png 768w, https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/generic-banners-protect-digital-life-1500x300-1.png 1500w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p><em>This post contains affiliate links. If you buy something through one of them, I may earn a small commission at no extra cost to you. Thanks for the support!<\/em><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let\u2019s be honest \u2014 keeping a fleet of Ubuntu servers updated isn\u2019t the most glamorous job, especially when they\u2019re tucked away behind firewalls with no internet access. But what if we could turn this dusty chore into a clean, elegant, and even satisfying little automation adventure? That\u2019s exactly what we did. This was actually my [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3709,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_FSMCFIC_featured_image_caption":"","_FSMCFIC_featured_image_nocaption":"","_FSMCFIC_featured_image_hide":"","footnotes":""},"categories":[7,62],"tags":[],"class_list":["post-3663","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux","category-network"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Secure and Centralized Ubuntu Patching with Ansible - IT-REACT<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Secure and Centralized Ubuntu Patching with Ansible - IT-REACT\" \/>\n<meta property=\"og:description\" content=\"Let\u2019s be honest \u2014 keeping a fleet of Ubuntu servers updated isn\u2019t the most glamorous job, especially when they\u2019re tucked away behind firewalls with no internet access. But what if we could turn this dusty chore into a clean, elegant, and even satisfying little automation adventure? That\u2019s exactly what we did. This was actually my [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/\" \/>\n<meta property=\"og:site_name\" content=\"IT-REACT\" \/>\n<meta property=\"article:published_time\" content=\"2025-04-17T11:27:19+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-04-19T22:49:01+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/2025-04-17-13-19-33-e1744889067554.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"570\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Ioan Penu\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ioan Penu\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/\"},\"author\":{\"name\":\"Ioan Penu\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#\\\/schema\\\/person\\\/bf08cffeb4b02ee6baff5d56ab17c8f0\"},\"headline\":\"Secure and Centralized Ubuntu Patching with Ansible\",\"datePublished\":\"2025-04-17T11:27:19+00:00\",\"dateModified\":\"2025-04-19T22:49:01+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/\"},\"wordCount\":1159,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#\\\/schema\\\/person\\\/bf08cffeb4b02ee6baff5d56ab17c8f0\"},\"image\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.it-react.com\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/2025-04-17-13-19-33-e1744889067554.png\",\"articleSection\":[\"Linux\",\"Network\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/\",\"url\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/\",\"name\":\"Secure and Centralized Ubuntu Patching with Ansible - IT-REACT\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.it-react.com\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/2025-04-17-13-19-33-e1744889067554.png\",\"datePublished\":\"2025-04-17T11:27:19+00:00\",\"dateModified\":\"2025-04-19T22:49:01+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.it-react.com\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/2025-04-17-13-19-33-e1744889067554.png\",\"contentUrl\":\"https:\\\/\\\/www.it-react.com\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/2025-04-17-13-19-33-e1744889067554.png\",\"width\":1024,\"height\":570,\"caption\":\"Photo generated with Dall-E by Ioan Penu\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/index.php\\\/2025\\\/04\\\/17\\\/secure-and-centralized-ubuntu-patching-with-ansible\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.it-react.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Secure and Centralized Ubuntu Patching with Ansible\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#website\",\"url\":\"https:\\\/\\\/www.it-react.com\\\/\",\"name\":\"it-react\",\"description\":\"Ctrl\u2022Alt\u2022Automate\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#\\\/schema\\\/person\\\/bf08cffeb4b02ee6baff5d56ab17c8f0\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.it-react.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.it-react.com\\\/#\\\/schema\\\/person\\\/bf08cffeb4b02ee6baff5d56ab17c8f0\",\"name\":\"Ioan Penu\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g\",\"caption\":\"Ioan Penu\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Secure and Centralized Ubuntu Patching with Ansible - IT-REACT","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/","og_locale":"en_US","og_type":"article","og_title":"Secure and Centralized Ubuntu Patching with Ansible - IT-REACT","og_description":"Let\u2019s be honest \u2014 keeping a fleet of Ubuntu servers updated isn\u2019t the most glamorous job, especially when they\u2019re tucked away behind firewalls with no internet access. But what if we could turn this dusty chore into a clean, elegant, and even satisfying little automation adventure? That\u2019s exactly what we did. This was actually my [&hellip;]","og_url":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/","og_site_name":"IT-REACT","article_published_time":"2025-04-17T11:27:19+00:00","article_modified_time":"2025-04-19T22:49:01+00:00","og_image":[{"width":1024,"height":570,"url":"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/2025-04-17-13-19-33-e1744889067554.png","type":"image\/png"}],"author":"Ioan Penu","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Ioan Penu","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/#article","isPartOf":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/"},"author":{"name":"Ioan Penu","@id":"https:\/\/www.it-react.com\/#\/schema\/person\/bf08cffeb4b02ee6baff5d56ab17c8f0"},"headline":"Secure and Centralized Ubuntu Patching with Ansible","datePublished":"2025-04-17T11:27:19+00:00","dateModified":"2025-04-19T22:49:01+00:00","mainEntityOfPage":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/"},"wordCount":1159,"commentCount":0,"publisher":{"@id":"https:\/\/www.it-react.com\/#\/schema\/person\/bf08cffeb4b02ee6baff5d56ab17c8f0"},"image":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/#primaryimage"},"thumbnailUrl":"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/2025-04-17-13-19-33-e1744889067554.png","articleSection":["Linux","Network"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/","url":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/","name":"Secure and Centralized Ubuntu Patching with Ansible - IT-REACT","isPartOf":{"@id":"https:\/\/www.it-react.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/#primaryimage"},"image":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/#primaryimage"},"thumbnailUrl":"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/2025-04-17-13-19-33-e1744889067554.png","datePublished":"2025-04-17T11:27:19+00:00","dateModified":"2025-04-19T22:49:01+00:00","breadcrumb":{"@id":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/#primaryimage","url":"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/2025-04-17-13-19-33-e1744889067554.png","contentUrl":"https:\/\/www.it-react.com\/wp-content\/uploads\/2025\/04\/2025-04-17-13-19-33-e1744889067554.png","width":1024,"height":570,"caption":"Photo generated with Dall-E by Ioan Penu"},{"@type":"BreadcrumbList","@id":"https:\/\/www.it-react.com\/index.php\/2025\/04\/17\/secure-and-centralized-ubuntu-patching-with-ansible\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.it-react.com\/"},{"@type":"ListItem","position":2,"name":"Secure and Centralized Ubuntu Patching with Ansible"}]},{"@type":"WebSite","@id":"https:\/\/www.it-react.com\/#website","url":"https:\/\/www.it-react.com\/","name":"it-react","description":"Ctrl\u2022Alt\u2022Automate","publisher":{"@id":"https:\/\/www.it-react.com\/#\/schema\/person\/bf08cffeb4b02ee6baff5d56ab17c8f0"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.it-react.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.it-react.com\/#\/schema\/person\/bf08cffeb4b02ee6baff5d56ab17c8f0","name":"Ioan Penu","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g","caption":"Ioan Penu"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/2a2a1b6be0f322a113eea11669895227e284c6091424d65be6c3c706c2822975?s=96&d=mm&r=g"}}]}},"_links":{"self":[{"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/posts\/3663","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/comments?post=3663"}],"version-history":[{"count":70,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/posts\/3663\/revisions"}],"predecessor-version":[{"id":3832,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/posts\/3663\/revisions\/3832"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/media\/3709"}],"wp:attachment":[{"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/media?parent=3663"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/categories?post=3663"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.it-react.com\/index.php\/wp-json\/wp\/v2\/tags?post=3663"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}