Important Settings of Amazon Linux 2 Which Can Be Done Using Ansible
Tags: aws, ec2, amazonlinux2, ansible
Published: 2022-04-27 16:38:00

Amazon Linux 2 is a Linux OS provided by AWS. Then, what’s the difference with other OS? The one thing we already know about it is that we don’t need to install AWS CLI when we need to perform any AWS command. I think that’s the most “striking part” that we don’t get it from the other OS.

More about Amazon Linux 2, click [here](https://aws.amazon.com/amazon-linux-2/?nc1=h_ls&amazon-linux-whats-new.sort-by=item.additionalFields.postDateTime&amazon-linux-whats-new.sort-order=desc)!

![Amazon Linux 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tkxg0j44x12ee4jzqvp1.png)

Then, have you tried to set up "important settings" for Amazon Linux 2? Here I mean the basic configurations to do before you are "completely" ready to use the server such as for production or any purposes such as hosting a web server or any other things. Here I summed them up into 5 things:

1. Doing update
    
2. Installing the app (should be done after the update). This is optional or can be executed at the last step, but I placed it on number two since I'll install a simple web server and will be executed after the update.
    
3. Managing user
    
4. Setting time zone (I'll skip NTP client configuration since Amazon already provided Time Sync by default).
    
5. Setting hostname
    

Alright! As I mentioned in the title, all those 5 things can be done with ansible. As we all know, ansible is a configuration management tool.

**Prerequisites:**

1. [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) and [set at least one credential](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html);
    
2. [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html);
    
3. Ansible collection for AWS by running `ansible-galaxy collection install amazon.aws` and `ansible-galaxy collection install community.aws`.
    

Before that, I'll launch an instance to be configured later.

Inventory: hosts.yml

```yaml
---

localhost:
  hosts:
    127.0.0.1:
```

Playbook: ec2.yml

```yaml
    - name: launch new instance
      amazon.aws.ec2_instance:
        name: amazonlinux2
        region: ap-southeast-3
        key_name: ec2-user
        instance_type: t3.micro
        security_group: ssh-web
        vpc_subnet_id: subnet-0276d466994fa3087
        network:
          assign_public_ip: true
          delete_on_termination: true
        image_id: ami-0de34ee5744189c60 
        volumes: 
          - device_name: /dev/xvda
            ebs: 
              volume_size: 8
              volume_type: gp2
              delete_on_termination: true
      tags:
        - ec2_new
```

Run the playbook!

```bash
$ ansible-playbook -i host.yml ec2.yml -t ec2_new

PLAY [ec2] **************************************************************************************************************************************************************

TASK [launch new instance] **********************************************************************************************************************************************
changed: [127.0.0.1]

PLAY RECAP **************************************************************************************************************************************************************
127.0.0.1                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

```bash
$ aws ec2 describe-instances --query 'Reservations[].Instances[].{ID:InstanceId, PrivateIP:PrivateIpAddress, PublicIP:PublicIpAddress, Name:Tags[?Key==`Name`].Value}'
[
    {
        "ID": "i-0187e4bb5d2f2007c",
        "PrivateIP": "10.0.1.7",
        "PublicIP": "108.136.226.235",
        "Name": [
            "amazonlinux2a"
        ]
    },
    {
        "ID": "i-050cfb6ee36a57131",
        "PrivateIP": "10.0.1.5",
        "PublicIP": "108.136.225.50",
        "Name": [
            "amazonlinux2"
        ]
    },
    {
        "ID": "i-09c46dba004ed7bd8",
        "PrivateIP": "10.0.2.8",
        "PublicIP": "108.136.235.232",
        "Name": [
            "amazonlinux2b"
        ]
    },
    {
        "ID": "i-02c7573fff1215e65",
        "PrivateIP": "10.0.3.11",
        "PublicIP": "108.136.150.180",
        "Name": [
            "amazonlinux2c"
        ]
    }
]
```

From the instances listed above, I'll use the `amazonlinux2` instance with IP 108.136.225.50.

## 1\. Doing update

By using `*` as the name, it will be turned into as `yum -y update`.

```yaml
- name: al2
  hosts: new
  become: true
  gather_facts: no
  tasks:
    - name: update
      yum:
        name: "*"
        state: latest
```

## 2\. Installing app

Here I'll only install the latest HTTPD for a simple web server.

```yaml
    - name: install web server
      yum:
        name: httpd
        state: latest

    - name: install web server
      service:
        name: httpd
        enabled: yes

    - name: modify home page
      shell: 'echo "Hello World!" >> /var/www/html/index.html'
```

## 3\. Management user

`ec2-user` is the default user of Amazon Linux 2. What if we have some people accessing the server using the same username? They may have made any changes and we will be in trouble to identify who has done it, right? So, we need to provide different user based on their names and roles. Let's say they're sysadmin. Then, we may also need to let them act as `sudoers` since we use SSH-key to connect to the EC2 instance and they need to have all access levels on the server without a password needed when they switch as sudo.

```yaml
    - name: create user
      user:
        name: nurulramadhona
        shell: /bin/bash

    - name: copy pubkey
      authorized_key:
        user: nurulramadhona
        state: present
        key: "{{ lookup('file', '/home/nurulramadhona/.ssh/id_rsa.pub') }}"

    - name: set user as sudoers
      lineinfile: 
        path: /etc/sudoers.d/90-cloud-init-users
        line: 'nurulramadhona ALL=(ALL) NOPASSWD:ALL'
        insertafter: EOF
```

## 4\. Setting timezone

(Please change to your local time zone)

```yaml
    - name: set timezone
      community.general.timezone:
        name: Asia/Jakarta
```

## 5\. Setting hostname

(Here I set the hostname for localdomain only, you can change it to your public domain if you have one and want to use it)

```yaml
    - name: preserve hostname
      lineinfile: 
        path: /etc/cloud/cloud.cfg
        line: 'preserve_hostname: true'
        insertafter: EOF

    - name: set hostname
      command: hostnamectl set-hostname {{ hostname }}.localdomain

    - name: replace localhost entry
      lineinfile: 
        path: /etc/hosts
        regexp: '^127\.0\.0\.1'
        line: '127.0.0.1   {{ hostname }}.localdomain {{ hostname }} localhost4 localhost4.localdomain4'
        owner: root
        group: root 
        mode: "0644"
```

Finally, when all tasks are ready. We have to add this to our inventory:

```yaml
new:
  hosts:
    108.136.225.50:
  vars:
    hostname: amazonlinux2
```

Now, let's run the playbook!

```bash
$ ansible-playbook -i host.yml al2.yml -u ec2-user

PLAY [al2] **************************************************************************************************************************************************************

TASK [update] ***********************************************************************************************************************************************************
changed: [108.136.225.50]

TASK [install web server] ***********************************************************************************************************************************************
changed: [108.136.225.50]

TASK [install web server] ***********************************************************************************************************************************************
changed: [108.136.225.50]

TASK [modify home page] *************************************************************************************************************************************************
changed: [108.136.225.50]

TASK [create user] ******************************************************************************************************************************************************
changed: [108.136.225.50]

TASK [copy pubkey] ******************************************************************************************************************************************************
changed: [108.136.225.50]

TASK [set user as sudoers] **********************************************************************************************************************************************
changed: [108.136.225.50]

TASK [set timezone] *****************************************************************************************************************************************************
changed: [108.136.225.50]

TASK [preserve hostname] ************************************************************************************************************************************************
changed: [108.136.225.50]

TASK [set hostname] *****************************************************************************************************************************************************
changed: [108.136.225.50]

TASK [replace localhost entry] ******************************************************************************************************************************************
changed: [108.136.225.50]

PLAY RECAP **************************************************************************************************************************************************************
108.136.225.50             : ok=11   changed=11   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

Let's check to remote the server again without specifying the default user. Since we already changed the hostname, we will also do a reboot.

```bash
$ ssh 108.136.225.50

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
[nurulramadhona@amazonlinux2 ~]$ sudo reboot
Connection to 108.136.225.50 closed by remote host.
Connection to 108.136.225.50 closed.
```

Let's verify the configurations by checking the hostname and time zone using Ansible ad-hoc!

```bash
$ ansible -i host.yml new -m shell -a "hostname && date"
108.136.225.50 | CHANGED | rc=0 >>
amazonlinux2.localdomain
Sun Apr 24 15:35:24 WIB 2022
```

That's it for Amazon Linux 2! On the next post, we will do deletion of what we have created (if you already followed all the previous posts in this series). Let's move to the next post!

**Reference:**

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Instances.html