{"id":106,"date":"2019-04-24T00:00:00","date_gmt":"2019-04-24T00:00:00","guid":{"rendered":"http:\/\/ssdnodes.billabailey.com\/2017\/04\/24\/tutorial-getting-started-with-ansible-and-configuration-management\/"},"modified":"2025-05-18T19:47:38","modified_gmt":"2025-05-18T19:47:38","slug":"ansible-tutorial-getting-started","status":"publish","type":"post","link":"https:\/\/www.ssdnodes.com\/blog\/ansible-tutorial-getting-started\/","title":{"rendered":"Getting started with Ansible for configuration management (Tutorial)"},"content":{"rendered":"<p>In this Ansible tutorial for beginners, we\u2019ll cover getting started with <a>Ansible<\/a> as a <em>configuration management<\/em> tool for setting up a bare CentOS, Debian, and Ubuntu server with more secure SSH settings and a few tools to make your life a little easier.<\/p>\n<p>Our goals:<\/p>\n<ol>\n<li>Set up a non-root user<\/li>\n<li>Give the new user sudo access<\/li>\n<li>Disable password-based logins<\/li>\n<li>Disable root logins<\/li>\n<li>Use SSH keys for logins<\/li>\n<\/ol>\n<h2>Prerequisites for this Ansible configuration management tutorial<\/h2>\n<ul>\n<li>A newly-provisioned or rebuilt server running any of our OS options\u2014CentOS, Debian, or Ubuntu.<\/li>\n<\/ul>\n<div class=\"cta-inline\"><\/div>\n<h2>Step 1: Install Ansible on your local machine<\/h2>\n<p>To get started using Ansible for configuration management, you first need to install it on your local machine. Ansible's documenation gives <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/installation_guide\/intro_installation.html\" target=\"_blank\" rel=\"noopener\">installation instructions<\/a> for a variety of platforms, including various *nix distributions and OS X.<\/p>\n<h2>Step 2: Edit the Ansible hosts file<\/h2>\n<p>To connect Ansible to your VPS, you need to specify its IP address within Ansible\u2019s hosts file. On Linux and OS X machines, that can be found at <code>\/etc\/ansible\/hosts<\/code>.<\/p>\n<p>The beginning of the file should look like this:<\/p>\n<pre class=\"hljs\"><code class=\"hljs shell\"><span class=\"hljs-meta\">#<\/span><span class=\"bash\"> This is the default ansible <span class=\"hljs-string\">'hosts'<\/span> file.<\/span>\n<span class=\"hljs-meta\">#<\/span>\n<span class=\"hljs-meta\">#<\/span><span class=\"bash\"> It should live <span class=\"hljs-keyword\">in<\/span> \/etc\/ansible\/hosts<\/span>\n<span class=\"hljs-meta\">#<\/span>\n<span class=\"hljs-meta\">#<\/span><span class=\"bash\">   - Comments begin with the <span class=\"hljs-string\">'#'<\/span> character<\/span>\n<span class=\"hljs-meta\">#<\/span><span class=\"bash\">   - Blank lines are ignored<\/span>\n<span class=\"hljs-meta\">#<\/span><span class=\"bash\">   - Groups of hosts are delimited by [header] elements<\/span>\n<span class=\"hljs-meta\">#<\/span><span class=\"bash\">   - You can enter hostnames or ip addresses<\/span>\n<span class=\"hljs-meta\">#<\/span><span class=\"bash\">   - A hostname\/ip can be a member of multiple groups<\/span>\n<span class=\"hljs-meta\">\n#<\/span><span class=\"bash\"> Ex 1: Ungrouped hosts, specify before any group headers.<\/span>\n<span class=\"hljs-meta\">\n#<\/span><span class=\"bash\"><span class=\"hljs-comment\"># green.example.com<\/span><\/span>\n<span class=\"hljs-meta\">#<\/span><span class=\"bash\"><span class=\"hljs-comment\"># blue.example.com<\/span><\/span>\n<span class=\"hljs-meta\">#<\/span><span class=\"bash\"><span class=\"hljs-comment\"># 192.168.100.1<\/span><\/span>\n<span class=\"hljs-meta\">#<\/span><span class=\"bash\"><span class=\"hljs-comment\"># 192.168.100.10<\/span><\/span>\n<\/code><\/pre>\n<p>To enable your VPS, simply add the IP address anywhere in this file underneath an <code>[ssdnodes]<\/code> grouping.<\/p>\n<p>There should be no other symbols\u2014like the <code>#<\/code> comment\u2014in the line.<\/p>\n<pre class=\"hljs\"><code class=\"hljs css\"><span class=\"hljs-selector-attr\">[ssdnodes]<\/span>\n123<span class=\"hljs-selector-class\">.45<\/span><span class=\"hljs-selector-class\">.67<\/span><span class=\"hljs-selector-class\">.89<\/span>\n<\/code><\/pre>\n<p>Now, test out your configuration by pinging your VPS. For now, you have to use <code>-u root<\/code> to ensure you\u2019re trying to connect via the root account.<\/p>\n<pre class=\"hljs\"><code class=\"hljs shell\"><span class=\"hljs-meta\">$<\/span><span class=\"bash\"> ansible all -m ping -u root<\/span>\n<\/code><\/pre>\n<p>If it\u2019s successful, you\u2019ll see the following output:<\/p>\n<pre class=\"hljs\"><code class=\"hljs javascript\"><span class=\"hljs-number\">123.45<\/span><span class=\"hljs-number\">.67<\/span><span class=\"hljs-number\">.89<\/span> | <span class=\"hljs-function\"><span class=\"hljs-params\">SUCCESS<\/span> =&gt;<\/span> {\n    <span class=\"hljs-string\">\"changed\"<\/span>: <span class=\"hljs-literal\">false<\/span>,\n    <span class=\"hljs-string\">\"ping\"<\/span>: <span class=\"hljs-string\">\"pong\"<\/span>\n}<\/code><\/pre>\n<h2>Step 3: Getting started with Ansible playbooks<\/h2>\n<p>To get started using Ansible to manage server configurations, we need to create an Ansible playbook. A playbook is the core component of any Ansible configuration.<\/p>\n<p>The playbook will define the tasks that need to be completed to configure your servers. The ability to create and run Playbooks is the key reason that it's so powerful to use Ansible for configuration management.<\/p>\n<p>The Ansible playbook is in the common <code>.yaml<\/code> language.<\/p>\n<pre class=\"hljs language-bash\"><code class=\"hljs\">$ mkdir ansible &amp;&amp; <span class=\"hljs-built_in\"><span class=\"hljs-built_in\">cd<\/span><\/span> ansible\n$ touch create_user.yaml\n$ nano create_user.yaml\n<\/code><\/pre>\n<p>And here is a basic playbook example that accomplishes our goals.<\/p>\n<p><strong>Note:<\/strong> This playbook is meant to run on a bare CentOS 7 server. If you want to run this on an Ubuntu\/Debian server, simply change the <code>yum<\/code> line to <code>apt<\/code>.<\/p>\n<pre class=\"hljs\"><code class=\"hljs sql\"><span class=\"hljs-comment\">---<\/span>\n- hosts: ssdnodes\n  remote_user: root\n\n  vars_prompt:\n\n    - name: \"user_name\"\n      prompt: \"Enter a name for the new user\"\n      private: no\n      confirm: yes\n\n    - name: \"user_password\"\n      prompt: \"Enter a password for the new user\"\n      private: yes\n      encrypt: \"sha512_crypt\"\n      confirm: yes\n      salt_size: 7\n\n  tasks:\n\n    - name: <span class=\"hljs-keyword\">Check<\/span> <span class=\"hljs-keyword\">to<\/span> make sure we have a <span class=\"hljs-string\">'wheel'<\/span> <span class=\"hljs-keyword\">group<\/span>\n      <span class=\"hljs-keyword\">group<\/span>:\n        <span class=\"hljs-keyword\">name<\/span>: wheel\n        state: <span class=\"hljs-keyword\">present<\/span>\n\n    - <span class=\"hljs-keyword\">name<\/span>: <span class=\"hljs-keyword\">Install<\/span> the <span class=\"hljs-string\">'sudo'<\/span> <span class=\"hljs-keyword\">package<\/span>\n      yum:\n        <span class=\"hljs-keyword\">name<\/span>: sudo\n        state: latest\n\n    - <span class=\"hljs-keyword\">name<\/span>: <span class=\"hljs-keyword\">Create<\/span> the non-root <span class=\"hljs-keyword\">user<\/span>\n      <span class=\"hljs-keyword\">user<\/span>:\n        <span class=\"hljs-keyword\">name<\/span>: <span class=\"hljs-string\">\"\"<\/span>\n        <span class=\"hljs-keyword\">password<\/span>: <span class=\"hljs-string\">\"\"<\/span>\n        shell: <span class=\"hljs-string\">\"\/bin\/bash\"<\/span>\n        <span class=\"hljs-keyword\">groups<\/span>: <span class=\"hljs-string\">\"wheel\"<\/span>\n\n    - <span class=\"hljs-keyword\">name<\/span>: <span class=\"hljs-keyword\">Add<\/span> <span class=\"hljs-keyword\">local<\/span> <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">key<\/span> <span class=\"hljs-keyword\">for<\/span> <span class=\"hljs-keyword\">key<\/span>-based SSH <span class=\"hljs-keyword\">authentication<\/span>\n      authorized_key:\n        <span class=\"hljs-keyword\">user<\/span>: <span class=\"hljs-string\">\"\"<\/span>\n        <span class=\"hljs-keyword\">key<\/span>: <span class=\"hljs-string\">\"{{item}}\"<\/span>\n      with_file:\n        - ~\/.ssh\/id_rsa.pub\n\n    - <span class=\"hljs-keyword\">name<\/span>: Restrict root SSH logins\n      lineinfile:\n        dest: \/etc\/ssh\/sshd_config\n        state: <span class=\"hljs-keyword\">present<\/span>\n        regexp: <span class=\"hljs-string\">'^#PermitRootLogin'<\/span>\n        line: <span class=\"hljs-string\">'PermitRootLogin no'<\/span>\n\n    - <span class=\"hljs-keyword\">name<\/span>: Restrict SSH logins <span class=\"hljs-keyword\">to<\/span> <span class=\"hljs-keyword\">keys<\/span> <span class=\"hljs-keyword\">only<\/span>\n      lineinfile:\n        dest: \/etc\/ssh\/sshd_config\n        state: <span class=\"hljs-keyword\">present<\/span>\n        regexp: <span class=\"hljs-string\">'^#PasswordAuthentication'<\/span>\n        line: <span class=\"hljs-string\">'PasswordAuthentication no'<\/span>\n\n    - <span class=\"hljs-keyword\">name<\/span>: Restart sshd\n      systemd:\n        state: restarted\n        daemon_reload: yes\n        <span class=\"hljs-keyword\">name<\/span>: sshd\n<\/code><\/pre>\n<p>Before we go into how you run this command, let\u2019s walk through what some of these lines do in practice.<\/p>\n<pre class=\"hljs\"><code class=\"hljs diff\"><span class=\"hljs-deletion\">- hosts: ssdnodes<\/span>\n  remote_user: root\n<\/code><\/pre>\n<p>These two lines dictate which host group we\u2019re going to work with\u2014in this case, the <code>ssdnodes<\/code> group we created earlier\u2014and specify that we\u2019re using the root login (just this once) to complete our steps.<\/p>\n<pre class=\"hljs\"><code class=\"hljs coffeescript\">vars_prompt:\n\n  - name: <span class=\"hljs-string\">\"user_name\"<\/span>\n    prompt: <span class=\"hljs-string\">\"Enter a name for the new user\"<\/span>\n    private: <span class=\"hljs-literal\">no<\/span>\n    confirm: <span class=\"hljs-literal\">yes<\/span>\n\n  - name: <span class=\"hljs-string\">\"user_password\"<\/span>\n    prompt: <span class=\"hljs-string\">\"Enter a password for the new user\"<\/span>\n    private: <span class=\"hljs-literal\">yes<\/span>\n    encrypt: <span class=\"hljs-string\">\"sha512_crypt\"<\/span>\n    confirm: <span class=\"hljs-literal\">yes<\/span>\n    salt_size: <span class=\"hljs-number\">7<\/span>\n<\/code><\/pre>\n<p>These two <code>vars_prompt<\/code> commands will ask for user input to define which username and password they would like to associate with the newly-created account.<\/p>\n<p>Beyond this, each nested block of script that begins with <code>- name:<\/code> defines a new task that Ansible will complete in sequential order, once the previous task has completed successfully. Failed tasks will cause the entire playbook to stop running.<\/p>\n<p>If you follow along with each of the tasks, you can see that we\u2019re installing <code>sudo<\/code>, creating our new user, adding your SSH public key to the server, and putting some basic restrictions on <code>sshd<\/code> before restarting it.<\/p>\n<h2>Step 4: Run the Ansible playbook<\/h2>\n<p>Running this Ansible playbook is fairly straightforward. Here\u2019s the command we\u2019ll use:<\/p>\n<pre class=\"hljs language-bash\"><code class=\"hljs\">ansible-playbook create_user.yaml --ask-pass\n<\/code><\/pre>\n<p>We need to include <code>--ask-pass<\/code> so that Ansible uses a password to log into the server rather than try to use an SSH key that isn\u2019t there.<\/p>\n<p>Once you run the command, you\u2019ll be asked to enter the <code>SSH password:<\/code>. This is the root login for your server\u2014that password can be found in your <a href=\"https:\/\/www.ssdnodes.com\/manage\/clientarea.php\">SSD Nodes dashboard<\/a>.<\/p>\n<p>Once you\u2019ve entered the root password, you\u2019ll be prompted to specify and confirm a username and password. Once that\u2019s done, Ansible will get to work!<\/p>\n<p>With any luck, Ansible runs smoothly, and you'll see the following in your terminal:<\/p>\n<pre class=\"hljs\"><code class=\"hljs nginx\"> <span class=\"hljs-attribute\">____________<\/span>\n&lt; PLAY RECAP &gt;\n ------------\n          <span class=\"hljs-regexp\"> ^__^<\/span>\n           (oo)_______\n            (__)       )\/\n                ||----w |\n                ||     ||\n\n<span class=\"hljs-number\">123.45.67.89<\/span>               : ok=<span class=\"hljs-number\">8<\/span>    changed=<span class=\"hljs-number\">6<\/span>    unreachable=<span class=\"hljs-number\">0<\/span>    failed=<span class=\"hljs-number\">0<\/span>  \n<\/code><\/pre>\n<p>At this point, you\u2019ll be able to log into your new user account using your SSH key.<\/p>\n<h2>More resources on Ansible for configuration management:<\/h2>\n<p>You\u2019re now ready to get started using Ansible to manage the configuration of new servers with ease, and with an eye toward security.<\/p>\n<p>For a deeper dive into getting started with Ansible, including in-depth explanations of all the components and terminology, check out our\u00a0<a href=\"https:\/\/www.ssdnodes.com\/blog\/step-by-step-ansible-guide\/\" target=\"_blank\" rel=\"noopener noreferrer\">&quot;Step by step guide to Ansible&quot; tutorial<\/a>.<\/p>\n<p>To get more concrete playbook examples aimed toward maximizing security-- to help you harden your SSH, fend off brute force attacks, and more-- check out our 2-part series:<\/p>\n<p><a href=\"https:\/\/www.ssdnodes.com\/blog\/secure-ansible-playbook\/\" target=\"_blank\" rel=\"noopener noreferrer\">Ansible playbook for a more secure VPS (part 1)<\/a><br \/>\n<a href=\"https:\/\/www.ssdnodes.com\/blog\/secure-ansible-playbook-2\/\" target=\"_blank\" rel=\"noopener noreferrer\">A More Secure Ansible Playbook (Part 2)<\/a><\/p>\n<p>And finally, for more information about how to use Ansible for automated server hardening, check out one these resources:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/dev-sec\/ansible-os-hardening\" target=\"_blank\" rel=\"noopener\">ansible-os-hardening<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dev-sec\/ansible-ssh-hardening\" target=\"_blank\" rel=\"noopener\">ansible-ssh-hardening<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/geerlingguy\/ansible-role-security\" target=\"_blank\" rel=\"noopener\">ansible-role-security<\/a><\/li>\n<\/ul>\n<p>[cta text2=&quot;You're 90 seconds away from running Ansible on an SSD Nodes cloud server!&quot; button=&quot;Ansible all the things!&quot;]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this Ansible tutorial, we\u2019ll cover using Ansible as a configuration management tool for setting up a bare CentOS, Debian, and Ubuntu server<\/p>\n","protected":false},"author":20,"featured_media":2135,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[18,30],"tags":[209],"class_list":["post-106","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","category-tutorials","tag-ansible"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts\/106","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/comments?post=106"}],"version-history":[{"count":4,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts\/106\/revisions"}],"predecessor-version":[{"id":13069,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts\/106\/revisions\/13069"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/media\/2135"}],"wp:attachment":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/media?parent=106"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/categories?post=106"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/tags?post=106"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}