Build a Useful Linux Login Banner On AWS With Ansible | by Tate Galbraith | Mar, 2022

Photo by Lukas on Unsplash

Most default Linux login banners (or MOTD) leave much to be desired. The login message isn’t something that is made to be left as is. It is made to be changed, customized and extended to suit specific use-cases. If you frequently access a lot of different cloud or on-premises servers, changing up the banner is almost a requirement.

The options for what you can include in your login banner are virtually endless. You can put everything from basic information about the server itself to a funny knock-knock joke of the day. The only limit is your imagination.

In this article, we’ll explore not only how to change this banner and what to put in it, but also how to deploy it with Ansible and include some handy AWS EC2 information inside.

Scraping EC2 instance metadata

If you haven’t used instance metadata before, you’re in for a real treat. Tucked away on most EC2 instance AMIs is the ability to gather basic information about the instance from within that instance’s OS. The instance exposes a local self-assigned IP address that provides a basic HTTP server for gathering information.

The metadata endpoint is usually exposed on the following self-assigned IPv4 address (it is only accessible locally):

http://169.254.169.254/latest/meta-data/

For example, from within the instance if you wanted to obtain the private IP you could run:

curl http://169.254.169.254/latest/meta-data/local-ipv4

This would return the private IP address currently assigned to this instance.

If we want to pull something like this into Ansible, all we have to do is make a simple web request from within our playbook. It would look something like this:

- name: Get EC2 instance metadata
uri:
url: "http://169.254.169.254/latest/meta-data/local-ipv4"
return_content: true
register: ec2_local_ip

Once this task completes, the private IP would be stored inside the resulting content key of the ec2_local_ip variable.

If you wanted to pull a more rich set of metadata about the instance you could use something called the “identity document”. This is a JSON blob full of information like instance type, private IP and more.

The identity document can be retrieved from the following path:

http://169.254.169.254/latest/dynamic/instance-identity/document

Note that this falls under the dynamic data and not meta-data key.

It looks something like this:

{
"accountId" : "123456789",
"architecture" : "x86_64",
"availabilityZone" : "us-west-1a",
"billingProducts" : null,
"devpayProductCodes" : null,
"marketplaceProductCodes" : null,
"imageId" : "ami-123456789",
"instanceId" : "i-00001234567890",
"instanceType" : "t2.micro",
"kernelId" : null,
"pendingTime" : "2022-01-21T00:47:18Z",
"privateIp" : "192.168.1.5",
"ramdiskId" : null,
"region" : "us-west-1",
"version" : "2017-09-30"
}

In order to retrieve this in Ansible, we’ll use a slightly different version of our request task and set a new variable:

- name: Get the instance identity document
uri:
url: "http://169.254.169.254/latest/dynamic/instance-identity/document"
return_content: true
register: identity_doc
- set_fact:
instance_metadata: "{{ identity_doc.json }}"

After this set of tasks completes we will be left with our identity document’s JSON blob loaded into the variable called instance_metadata.

Now, let’s look at how to build out the basic playbook to actually replace the banner with some of this info.

Building the playbook

In order to change the banner we’ll need to setup a simple task within our playbook for this. In almost all cases, you’ll just want to replace the whole banner with something custom. In this example we will be templating the entire file:

- name: Change MOTD banner
template:
src: motd.j2
dest: /etc/motd
register: motd_file
- name: Restart ssh when updated
service:
name: ssh
state: restarted
when: motd_file.changed

In the task above we are taking our template file and applying it over top of the existing motd path. Then, assuming the file has been changed, we restart the ssh service. This is important because the login banner won’t be picked up unless you restart the service.

Note: Depending on your Linux distribution, the service may be called something other than ssh.

Now, let’s look at how to build the template itself.

Building the template

Ansible templates are very powerful features. Within a role or a playbook you can setup template files that are capable of generating very complex text layouts. You can template configuration files and much more using this engine.

For this example we will interpolate the metadata we gathered and build a more aesthetically pleasing layout.

Create a file called motd.j2 (either within the templates directory of your role or in the same directory as the playbook) and let’s start building the basic template:

()================================================================()          host:   {{ ansible_host }}
kernel: {{ ansible_kernel }}
instance-id: {{ instance_metadata.instanceId }}
instance-type: {{ instance_metadata.instanceType }}
private-ip: {{ instance_metadata.privateIp }}
()===============================================================()

In this template we are doing a few simple things like formatting with tabs and line breaks, but we also pull in a number of variables from the instance identity document along with internal Ansible variables.

Remember that in our playbook we’ve stored the identity document in a variable called instance_metadata so we can access it just like a normal dictionary and reference these variables within our template.

Let’s take a look at what the final playbook would look like.

Putting it all together

Below is an example playbook which would run against localhostgather metadata and change the banner to our new template:

---
- hosts: localhost
tasks:
- name: Get the instance identity document
uri:
url: "http://169.254.169.254/latest/dynamic/instance-identity /document"
return_content: true
register: identity_doc
- set_fact:
instance_metadata: "{{ identity_doc.json }}"
- name: Change MOTD banner
template:
src: motd.j2
dest: /etc/motd
register: motd_file
- name: Restart ssh when updated
service:
name: ssh
state: restarted
when: motd_file.changed

Depending on your specific Linux distribution’s SSH configuration you may need to update the SSH daemon’s to support using the MOTD.

In Debian this is located in /etc/ssh/sshd_config. Removing or commenting out the Banner line should do the trick and allow MOTD to be displayed.

If you still run into trouble, you may also need to disable any dynamic MOTD scripts located in /etc/update-motd.d.

Once you’ve put everything together and run the playbook against your EC2 host, you should see a pleasant new login banner similar to this:

Dynamic login banner on EC2 host.

Now you will have access to basic EC2 information right when you login. This saves time and ensures you login to the correct host, with the correct configuration.

You can extend this login banner to feature even more information from instance metadata and Ansible. If you’re in the mood for something more fun you could add features like Cowsay or Fortune.

Leave a Comment