Specify User per Task in Ansible

become_user per task in Ansible

Turns out, become_user directive can be used not only for privilege escalation (running Ansible playbooks as root), but also for becoming any other when you want certain tasks run as that user instead of root.

Default Ansible Behavior for Running Tasks

I had the following piece of code, running /home/greys/.dotfiles/install script. It didn’t run as intended, creating symlinks in /root directory (because that’s what Ansible was running the task as):

- name: Create symlinks for dotfiles
  shell: /home/greys/.dotfiles/install
  register: dotfiles.result
  ignore_errors: yes
  tags: 
    - dotfiles

Specify User for an Ansible Task

become_user parameter can be specifed per task or per playbook, apparently. So that’s how you specify it per task – in my example to run the Create symlinks for dotfiles task as my user greys:

- name: Create symlinks for dotfiles
  shell: /home/greys/.dotfiles/install
  register: dotfiles.result
  ignore_errors: yes
  become: yes
  become_user: greys
  tags: 
    - dotfiles

See Also




Setting Alternatives Path for Python Command in RHEL 8

alternatives: python to /usr/bin/python3

Red Hat Enterprise Linux 8 comes with support for both Python 2 and Python 3. But neither of them is invoked via running python command – you get “command not found” error.

Default Python Version in RHEL 8

Python 3.6 is the default and primary version of Python in RHEL 8. It may need to be istalled, but in my VirtualBox VM installation of RHEL 8 beta it came preinstalled.

Check Python 3 version

Just type python3 to see which version you have:

[greys@rhel8 ~]$ python3
Python 3.6.6 (default, Oct 16 2018, 01:53:53)
[GCC 8.2.1 20180905 (Red Hat 8.2.1-3)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>    

Python Command Not Found

If we type python instead of python3, we’ll get the following error:

[greys@rhel8 ~]$ python
bash: python: command not found…

Set Alternatives Path For Python to Python3

There’s a special alternatives method in Red Hat Linux and CentOS, it allows you to select the primary version of a tool when multiple versions are available. Among other things, alternatives command (must be run as root) can create default paths.

This command configures RHEL to invoke /usr/bin/python3 whenever you run python:

[greys@rhel8 ~]$ sudo alternatives --set python /usr/bin/python3
[sudo] password for greys:

That’s it! If you type python again, you’ll see python3 executed instead of getting an error:

[greys@rhel8 ~]$ python
Python 3.6.6 (default, Oct 16 2018, 01:53:53)
[GCC 8.2.1 20180905 (Red Hat 8.2.1-3)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>    

Have fun!




Show Monitor Resolutions with xrandr

Unix Tutorial

One of the things still left to be done on my Ubuntu laptop is to get the full resolution output on my LG 5K monitor. This is still work in progress, but one of the most useful tools for getting there is xrandr.



What is RandR

You may know that most of Linux laptops and desktops are using X11 or Xorg graphics system for providing core functionality to higher level graphics environments like Gnome, MATE or KDE.

RandR is one of the most common modules of X11/Xorg, it’s a plugin implementing basic Resize, Rotate and Reflect – RandR for short.

xrandr command

xrandr is a great command line utility that provides low-level management of your displays, detecting monitor resolutions and adding new display modes.

Here’s the most basic way of using xrandr: simply run it without parameters to see all the attached graphics devices and their resolutions:

greys@xps:~ $ xrandr
Screen 0: minimum 320 x 200, current 4096 x 2304, maximum 8192 x 8192
eDP-1 connected (normal left inverted right x axis y axis)
3840x2160 60.00 + 59.98 59.97
3200x1800 59.96 59.94
2880x1620 59.96 59.97
2560x1600 59.99 59.97
2560x1440 59.99 59.99 59.96 59.95
2048x1536 60.00
1920x1440 60.00
1856x1392 60.01
1792x1344 60.01
2048x1152 59.99 59.98 59.90 59.91
1920x1200 59.88 59.95
1920x1080 60.01 59.97 59.96 59.93
1600x1200 60.00
1680x1050 59.95 59.88
1600x1024 60.17
1400x1050 59.98
1600x900 59.99 59.94 59.95 59.82
1280x1024 60.02
1440x900 59.89
1400x900 59.96 59.88
1280x960 60.00
1440x810 60.00 59.97
1368x768 59.88 59.85
1360x768 59.80 59.96
1280x800 59.99 59.97 59.81 59.91
1152x864 60.00
1280x720 60.00 59.99 59.86 59.74
1024x768 60.04 60.00
960x720 60.00
928x696 60.05
896x672 60.01
1024x576 59.95 59.96 59.90 59.82
960x600 59.93 60.00
960x540 59.96 59.99 59.63 59.82
800x600 60.00 60.32 56.25
840x525 60.01 59.88
864x486 59.92 59.57
800x512 60.17
700x525 59.98
800x450 59.95 59.82
640x512 60.02
720x450 59.89
700x450 59.96 59.88
640x480 60.00 59.94
720x405 59.51 58.99
684x384 59.88 59.85
680x384 59.80 59.96
640x400 59.88 59.98
576x432 60.06
640x360 59.86 59.83 59.84 59.32
512x384 60.00
512x288 60.00 59.92
480x270 59.63 59.82
400x300 60.32 56.34
432x243 59.92 59.57
320x240 60.05
360x202 59.51 59.13
320x180 59.84 59.32
DP-1 connected (normal left inverted right x axis y axis)
2560x2880 60.00
DP-2 connected primary 4096x2304+0+0 (normal left inverted right x axis y axis) 600mm x 340mm
3840x2160 60.00 +
4096x2304 60.00*
3200x1800 60.00
2560x1440 60.00
640x480 59.94

Understanding the xrandr output

Structured output lists multiple monitors connected: eDP (embedded Display Port – this is used for the primary laptop screen) and DP-1/DP2 – which are Display Ports for external connections.

I have highlighted the 4K resolution I’m getting so far, and think additional trickery would be needed to get this monitor show its true 5K (5120×2880) resolution. Stay tuned!

See Also




Deploy Your SSH key To Remote Server

Adding SSH key to remote server

One of the greatest improvements introduced by the SSH protocol is key-based authentication – meaning your client and SSH server establish validity of your SSH keypair and let you gain remote SSH access without asking for your password.



SSH Authentication with Passwords

By default, SSH server will ask for your password when you’re trying to connect. Unless you specify a username, your SSH client will set it automatically to your username on local (client) system:

Connecting to remote server using SSH

In this example above, I’m running command line (iTerm2) session on my Macbook. greys is my local username, maverick is the hostname on my Macbook. I’m typing ssh command and specifying the server to connect to – with hostname becky.

As you can see, next thing that happens is that I get a password prompt.

How Key Based SSH Access Works

Key-based SSH authentication takes an extra step to setup but then saves you tons of time in the future:

  • you deploy your public SSH key to remote server (need to type SSH password for possibly the last time)
  • you start SSH agent to load your private SSH key and to use it for remote connections
  • you connect to the remote SSH server without typing any passwords – still enjoying the same great benefits like encryption and traffic compression that SSH brings

Deploy Your Public SSH Key to Remote Server

You guessed it right! There’s actually a command for that, it’s called ssh-copy-id. What it does is connect to remote SSH server using username and password that you supply and then edit the .ssh/authorized_keys there to include your public key.

When running ssh-copy-id, you need to specify 2 things at a minimum:

  1. The SSH identity (name of a key you want to deploy)
  2. The SSH server name (where you want to add your key to)

Here’s how it works:

greys@maverick:~ $ ssh-copy-id -i .ssh/id_ed25519 becky
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: ".ssh/id_ed25519.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
[email protected]'s password:

Number of key(s) added:        1

Now try logging into the machine, with:   "ssh 'becky'"
and check to make sure that only the key(s) you wanted were added.

Next time you attempt to connect, your ssh client will offer remote server a list of SSH identities you have configured on your client. In most recent Unix-like distros you have an SSH agent starting with your graphics login – it’s called GNOME Keyring or or Keychain in MacOS (and there’s plenty of ways to start ssh-agent during startups of sessions like KDE).

The bottom line is that when I try to connect to becky now, my SSH key is offered and, if it’s available (loaded in ssh-agent), I get a passwordless SSH access to remote server:

That’s it for today, have fun!

See Also




Advice: Safely Removing a File or Directory in Unix

Unix Tutorial

Removing files and directories is a very common task, so in some environments support engineers or automation scripts delete hundreds of files per day. That’s why I think it’s important to be familiar with different ways and safety mechanisms you should use when it comes to removing Unix directories. This article has a number of principles that should help you make your day-to-day files and directories operations safer.



DISCLAIMER: one can never be too careful when using a command line, and removing files or directories in Unix is not an exception. That’s why please take extra care and spend time planning and understanding commans and command line options before executing them on production data. I’m sharing my own advice and my approach, but DO YOUR OWN RESEARCH as I accept no responsibility for any possible loss cuased by direct or indirect use of the suggested commands.

Safely Removing Files and Directories

Advice in this article is equally applicable to commands you type and to the automation solutions you create. Be it a single command line or a complex Ansible playbook – safety mindset should be applied whenever you’re creating an actionable plan for working with important data.

If you can think of any more advice related to this topic, please let me know!

1. Double-check Directories Before Removing

I wouldn’t call this out if it hasn’t saved me so many times. No matter who made the request, no matter how urgent the task is, no matter how basic and obvious the directory name seems, always double-check directories before removing!

Basic approach is: replace rm/rmdir with ls -l command.

So instead of

$ rm -rf /etc /bin

you type ls command and review the output:

$ ls -l /etc /bin

Things you’re checking for are:

  1. Is this a user/task specific directory or a global directory?
  2. Does it seem to be part of the core OS?
  3. Will removing these files break any functionality you can think of?
  4. Does the directory contain any files?
  5. Does the number of files seem different from what you expected?

For instance: you’re asked to delete an empty directory. Do a quick ls, and if it has files – double-check if they should be deleted as well. Also, check if it’s one of the common core OS directories like /etc or /bin or /var – it could be that you got the name by mistake but removing directory without checking would become an even bigger mistake.

2. Consider Moving Instead of Removing

In troubleshooting, many requests are made so that you free up a directory or tidy up filesystem structure. But the issues are mostly around file and directory names, rather than the space they take up.

So if filesystem space is not an issue right now, consider moving the directory instead of removing (deleting) it completely:

$ mv /home/greys/dir1 /home/greys/dir1.old

The end result will be that /home/greys/dir1 directory is gone, but you still have time to review and recover files from /home/greys/dir1.old if necessary.

3. Use root Privilege Wisely

Hint: don’t use root unless you absolutely have to. If the request is to remove a subdirectory in some application path – find out what user the application is running as and become that user before removing the directory.

For instance:

# su - javauser
# rm -rf /opt/java/logs/debug

Run as root user, this will let you become a javauser and attempt to remove the /opt/java/logs/debug directory (debug subdirectory in /opt/java/logs directory).

If there’s an issue (like getting permissions denied error) – review and find out what the problem is instead of just becoming root and removing the directory or files anyway. Specifically: permission denied suggests that files belong to another user or group, meaning they are potentially used and needed for something else and not just the application you’re working on.

4. Double-check Any Masks or Variables

If you’re dealing with expanding filename masks, double-check them to have correct and non-zero values.

Consider this:

$ rm -rf /${SOMEDIR}

if you’re not careful validating it, then it’s quite possible that $SOMEDIR is not initialised (or initialised under some other user session), thus resulting in the vastly different command with catastrophic results (yes, I know: this exact example below is NOT that bad, because as regular user it simply won’t work. But run as run will result in OS self-destruct):

$ rm -rf /

Similarly, if there are filenames to be expanded, verify that expansion works as intended. Very important thing to realise is that your filename masks will be expanded as your current user.

$ <SUDO> rm /$(ls /root) 
ls: cannot access '/root/': Permission denied
 rm: cannot remove '/': Is a directory

This example above is using shell expansion: it runs ls /root command that will return valid values if you have enough permissions. But run as regular use this will give an error and also alter the path used for the rm command. It will be as if you tried to run the following with sudo privileges:

$ rm /

Again, I’m not giving you the full commans as it’s all too easy to break your Unix like OS beyond repair when you run full commands as root without double-checking.

5. echo Each Command Before Running

The last principle I find very useful is to prepend any potentially dangerous command with echo. This means your shell will attempt expanding any command line parameters and substitutions, but then show the resulting command line instead of actually executing it:

greys@becky:~ $ echo rm -rf /opt/java/logs/${HOSTNAME}
rm -rf /opt/java/logs/becky

See how it expanded ${HOSTNAME} variable and replaced it with the actual hostname, becky?

Use echo just to be super sure about what you think the Unix shell will execute.

That’s it for today, hope you like this collection of safety principles. Let me know if you want more articles of this kind!

See Also

return nothing




Using Multiple SSH ports

Unix Tutorial

This is not the most obvious functionality, hence I decided to share it as a separate post. It’s quite easy and perfectly acceptable to specify more than one SSH port for your sshd daemon – useful for debugging or added security (when bound to separate IP addresses).

Adding Extra SSH ports

Simply edit the /etc/ssh/sshd_config file and add more port numbers under the existing default port (it’s commented out because 22 is used by default):

greys@server:~$ sudo vi /etc/ssh/sshd_config

Change this:

#Port 22
AddressFamily any±
ListenAddress 0.0.0.0
ListenAddress ::

to this:

Port 22
Port 221
Port 222

AddressFamily any±
ListenAddress 0.0.0.0
ListenAddress ::

IMPORTANT: you must uncomment Port 22, otherwise new ports will be the only SSH ports listened on (so SSH port 22 will stop working).

Now restart ssh:

greys@server:~$ sudo systemctl restart ssh

Confirm each new SSH port

netstat command with grep confirms that all 3 ports are being listened on now:

greys@server:~$ netstat -nal | grep 22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:221 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:222 0.0.0.0:* LISTEN

If we want to, we can even try connecting to a non-standard ssh port like 221 or 222 as per our changes.

Don’t be alarmed about warning:

root@server:~# ssh greys@localhost -p 222
The authenticity of host '[localhost]:222 ([127.0.0.1]:222)' can't be established.
ECDSA key fingerprint is SHA256:12efZx1MOEmlxQOWKhM5eaxDwJr4vUlLhcpElkGHTow.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:222' (ECDSA) to the list of known hosts.
greys@localhost's password:
Welcome to Ubuntu 19.04 (GNU/Linux 4.18.0-20-generic x86_64)

Hope you enjoy this advice, stay tuned for more!

See Also




Great Things You Can Confirm with dmidecode

dmidecode-command

I’ve just started working on the Linux Commands section of Unix Tutorial, and dmidecode is one of the best commands to mention when it comes to recent Linux distros. It’s found in most distributions and helps with learning lots of useful facts about your environments – both physical and virtual.

How To Use dmidecode Command

dmidecode command needs to be run as root and shows you hardware information about your system:

  • BIOS name and version
  • manufacturer of your server, desktop or laptop
  • model name and serial number of your system

Simply run the command and pipe it to a pager like more or less:

greys@xps:~ $ sudo dmidecode | less
# dmidecode 3.2
Getting SMBIOS data from sysfs.
SMBIOS 3.2.1 present.
# SMBIOS implementations newer than version 3.2.0 are not
# fully supported by this version of dmidecode.
Table at 0x000E0000.

Handle 0x0000, DMI type 0, 26 bytes
BIOS Information
Vendor: Dell Inc.
Version: 1.2.1
Release Date: 02/14/2019
Address: 0xF0000
Runtime Size: 64 kB
ROM Size: 32 MB
...

Browsing dmidecode output and searching through the output are the best ways to use dmidecode command, but once you become familiar with your environment you’ll probably get a few dmidecode parameters you can grep for.

Hardware Vendor with dmidecode

This will report the manufacturer of your system. For my XPS laptop, it shows Dell:

greys@xps:~ $ sudo dmidecode | grep Vendor
Vendor: Dell Inc.
Vendor ID:

Model name with dmidecode

Look for the Product Name to confirm the name of your system. It shows my laptop’s model for me:

greys@xps:~ $ sudo dmidecode | grep Product
Product Name: XPS 13 9380
Product Name: 0KTW76

Motherboard with dmidecode

Finding the motherboard model will require you to search through the less pager output (press / and start typing word motherboard, then scroll up and down).

Here’s what one of my dedicated servers shows:

Handle 0x0002, DMI type 2, 15 bytes
Base Board Information
Manufacturer: Supermicro
Product Name: X11SSE-F
Version: 1.01
Serial Number: ZM163S009892
Asset Tag: To be filled by O.E.M.
Features:
Board is a hosting board
Board is replaceable
Location In Chassis: To be filled by O.E.M.
Chassis Handle: 0x0003
Type: Motherboard
Contained Object Handles: 0

Serial numbers with dmidecode

Just grep for the word Serial to find lots of serial numbers of various recognised devices. One of them (the first one in the output) is the Dell’s service tag that you usually need for hardware support:

greys@xps:~ $ sudo dmidecode | grep Serial
Serial services are supported (int 14h)
Serial Number: 50G8V**
Serial Number: /50G8V**/CN***00***00F8/
Serial Number: 50G8V**
Serial Number: Not Specified
Serial Number: Not Specified
Serial Number: To Be Filled By O.E.M.
Serial Number: 0A3E
Debug Use USB(Disabled:Serial)

There’s lots of other things dmidecode is useful for – I’ll be sure to update the dmidecode command page going forward.

See Also




Show Servers Across All OpenStack Projects

openstack-logo.png

I’m positive that sometime later this year I’ll revisit OpenStack basics, but for now there’s just no time. This post is one of those as-we-go technical notes taken for my own reference.

List OpenStack Servers using CLI

Once your OpenStack environment variables are configured, you can list servers using a very simple command:

$ openstack server list

But since one of the OpenStack variables is default project, the command above will probably just get you the list of servers within that project.

List OpenStack Servers Across All Projects

Provided your username and password have enough access, it should be possible to expand the previous command to get you a much longer list – namely every OpenStack server in every project available:

$ openstack server list --all-projects

See Also




Create swap from File on BTRFS Filesystem

mkswap-swapon

I didn’t create any swap during initial Ubuntu 19.04 install on Dell XPS laptop, so had to improvise when compiling a massive opensource project recently. This post shows you how to temporarily add swap memory using a regular file.

Create swap Using Regular File

The usual approach is fairly simple:

  • you create a large enough file (the desired size of your swap memory) – 1GB or 4GB or something like that
  • you initialise it as swap
  • you activated it as swap

Swap Files Support in BTRFS

Since I’ve used BTRFS filesystem for root in my Ubuntu setup, I discovered that there are additional steps needed: BTRFS filesystem creates and writes files in a way that’s been mostly incompatible with swap usage.

But as luck would have it, BTRFS supports swap files with Linux Kernel 5.0.x, so you just need to create file with specific attribute.

Swap Space Using File Procedure

Step 1: Create new empty file

We need to create a file with NOCOW (NO Copy-On-Write) property (no harm anywhere but is a requirement for BTRFS):

root@xps:/ # touch /swapfile
root@xps:/ # chattr +C /swapfile

Step 2: Allocate required amount of space to the file

root@xps:/ # fallocate -l 8G /swapfile

This file is 8GB now:

root@xps:/ # ls -ald /swapfile 
-rw------- 1 root root 8589934592 Jul 17 19:55 /swapfile

Step 3: Update permissions

root@xps:/ # chmod 0600 /swapfile 

Step 4: Initialise /swapfile as swap storage

root@xps:/ # mkswap /swapfile 
Setting up swapspace version 1, size = 8 GiB (8589930496 bytes)
no label, UUID=16d35c04-78de-4dd3-aeb0-e2228bb7ce36

Step 5: Activate swap space from /swapfile

root@xps:/ # swapon /swapfile

Step 6: Confirm newly activated swap space

root@xps:/ # free -h
total used free shared buff/cache available
Mem: 15Gi 6.1Gi 1.7Gi 3.1Gi 7.5Gi 5.8Gi
Swap: 8.0Gi 0B 8.0Gi

That’s it for today!

See Also




Free Up Reserved Space in Filesystems

tune2fs-reserved-space

You’re probably familiar with tune2fs command, it’s great for reporting filesystem layout and configuration options. It’s also helpful when you want to free up some of the reserved space.

Reserved Space in Unix/Linux Filesystems

Reserved space is one of the more mysterious things in Linux/Unix filesystems. A rather old tradition,  it is simply a practice of automatically reserving some filesystem space for system (superuser) use. When you’re formatting a new filesytem, it automatically reserves 5% of space for superuser access – meaning regular users and processes won’t be able to use this space (filesystem will report to be 100% full), but root user can still write and troubleshoot.

Reserved Space meant a lot more convenience when hard disks and filesystems were small – about 20 years ago your / or /var filesystem could be 1GB in total, and this meant it was absolutely crucial to reserve some space so that regular users could not cause an outage by generating some temporary file and filling up a key filesystem. These days sizes of filesystem are vastly larger and this means two things:

  1. You probably don’t benefit from reserved space as much as someone used to
  2. You may well never even know you had space reserved because you simply don’t run out of space

Here’s how this would look:

root@xps:/storage # df -h /storage
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p8 95G 90G 232M 100% /storage

Doesn’t quite add up, does it? It’s a 95GB filesystem with only 90GB used, yet filesystem is 100% full.

Change Reserved Space Percentage with tune2fs

Let’s use tune2fs command to reduce the percentage of reserved space (-m 1 means set reserve to 1% of total capacity):

root@xps:/storage # tune2fs -m 1 /dev/nvme0n1p8 
tune2fs 1.44.6 (5-Mar-2019)
Setting reserved blocks percentage to 1% (254279 blocks)

… and enjoy the results:

root@xps:/storage # df -h /storage 
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p8 95G 90G 4.2G 96% /storage

That’s it for today, hope you learned something new!

See Also