Using different sudo passwords for the same host group in Ansible

I'll write this down here before I forget.

I have 2 VPSs that I manage with Ansible and recently I updated the root password for one of the servers, and my old playbook, which worked fine if all the hosts in the group have the same password, stopped working.

I tried some stuff that didn't work, until I found out that the way to solve this is described in this link:

Ansible - Become

Basically I added a connection variable called ansible_become_pass for each of my servers, and assigned them with the variable names inside of my Vault. Like this:

[vps]
foo.com ansible_user=foo ansible_ssh_private_key_file=/server/id_rsa_foo ansible_become_pass='{{ foo_sudo_pass }}'
bar.foo.com ansible_user=bar ansible_ssh_private_key_file=/server/id_rsa_bar ansible_become_pass='{{ bar_sudo_pass }}'

The variables foo_sudo_pass and bar_sudo_pass are the root passwords for each server and they are stored in my Vault file (called passwords.yml).

Those variables will be readed at the time the playbook is executed... So you could have something as simple as this:

$ cat upgradeAll.yml
---
- hosts: vps
  become: true
  tasks:
  - name: "apt-get update"
    apt:
      upgrade: dist
      update_cache: yes
      cache_valid_time: 7200

And run the playbook with the verbose option to get some more information with this command:

$ ansible-playbook upgradeAll.yml -e@/server/playbooks/passwords.yml --vault-password-file vault_pass.txt -v

Let's see an example:

$ ansible-playbook upgradeAll.yml -e@/server/playbooks/passwords.yml --vault-password-file vault_pass.txt  -v
PLAY [vps] 
*********************************************************************************

TASK [Gathering Facts] 
*********************************************************************************
ok: [foo.com]
ok: [bar.foo.com]

TASK [read vars] 
*********************************************************************************
ok: [foo.com] => {"ansible_facts": {"foo_sudo_pass": "pass1", "bar_sudo_pass": "pass2", "test_sudo_pass": "testpass"}, "changed": false}
ok: [bar.foo.com] => {"ansible_facts": {"foo_sudo_pass": "pass1", "bar_sudo_pass": "pass2", "test_sudo_pass": "testpass"}, "changed": false}

TASK [apt-get update] 
*********************************************************************************
changed: [foo.com] => {"changed": true, "msg": "Reading package lists.
[...]

PLAY RECAP 
*********************************************************************************
foo.com                : ok=3    changed=1    unreachable=0    failed=0
bar.foo.com            : ok=3    changed=1    unreachable=0    failed=0

$

It is interesting to notice how I added the extra variables in the command by using -e@/server/playbooks/passwords.yml, otherwise it won't work!

Later!

Interview question: chmod chmod?

Not sure why, today I remembered about a question from a job interview I did probably 5 years ago... It was a pretty easy question, and my answer was pretty dumb.

Q: "Ok, imagine you remove execution permissions to chmod... How would you put them back???"

A: "quick and dirty, I'd copy the binary from the machine sitting next to it".

How about that? I remember it was very late in the evening (I was working in Tokyo at that time and they called me from Europe), but anyway, there was no excuse. I think they guy who interviewed me is still laughing :)

There are multiple ways to solve it. Using perl, python, go, C++, etc allows you to change the permissions of any file, including chmod... Let me show you how I'd do it in python:

#Current permissions: 755
root@94d9407f1002:/# # ls -l /bin/chmod
-rwxr-xr-x 1 root root 56112 Feb 18  2016 /bin/chmod

#Let's remove execution permission
root@94d9407f1002:/# chmod -x /bin/chmod

#New permissions: 644 
root@94d9407f1002:/# ls -l /bin/chmod
-rw-r--r-- 1 root root 56112 Feb 18  2016 /bin/chmod

#Checking execution is not allowed
root@94d9407f1002:/# chmod +x /bin/chmod
bash: /bin/chmod: Permission denied

#Here comes python to the rescue
root@94d9407f1002:/# python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.chmod("/bin/chmod",0o755)
>>> exit()

#Confirming it worked as expected
root@94d9407f1002:/# ls -l /bin/chmod
-rwxr-xr-x 1 root root 56112 Feb 18  2016 /bin/chmod

Not sure why this came to my mind today... But in case someone asks you this very same question, don't f$ck it up as I did. Just breathe normally, and think...

\\psgonza

All the images missing... Thanks Dropbox :(

I bet nobody noticed but all the images in the blog were not here anymore... No pictures, no logo, etc. Ooops!

I was using dropbox as storage for the blog images, and a while ago they decided to change the policy about their public folders. Bummer!

I don't think Dropbox is to blame here though. They provide a really good service (for free!) and I guess they have to draw a line somewhere.

Anyway, I will be storing the images in the server from now on, so I am updating the posts and changing the image paths.

Bye

Simple Vigenere cipher in Python (and 3)

See: - Part 1/3 - Part 2/3

Last part of my series about Vigenere cipher. (3 post in a row? I am proud of myself :-P)

In my previous posts I already showed how to use Vigenere square to encrypt/decrypt text, so this time I'll follow the algebraic method described in the Wikipedia:

{% img center https://bynario.com/img/vigenere.jpg 'vigenere' %}

I'll use the same input, same key, and same alphabets as in previous exercises:

mykey:  "WHITE" 
input_text:  "en un lugar dela mancha de cuyo nombre no quiero acordarme" 
Position:           00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 
Ref alphabet(M):    A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z 
Key alphabet(K):    B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  A 

(In the reference alphabet,we have shifted the letters one position, as the author did in the book, so K alphabet starts in "B" not in "A"

Encryption:

Now we are going to use numbers instead of the square approach.

If you remember the first post, the foundation of this cipher is the tuple (letter,key):

INPUT: EN UN LUGAR DE LA MANCHA
KEY:   WH IT EWHIT EW HI TEWHIT
TUPLE: ('E', 'W'),('N', 'H'),('U', 'I'),('N', 'T'), ('L', 'E'),('U', 'W'),[...]

Let's get the positions of each element in the tuple in M[] and K[]:

1st tuple: 'E' is in position 4 in our reference alphabet(M). 'W' is in position 21 in the Key alphabet(K)
2nd tuple: 'N' is in position 13 in M[], 'H' is in position 6 in K[]
3rd tuple: 'U' is in position 20 in M[], 'I' is in position 7 in K[]

('4','21'),('13','6'),('20','7'),('13','18'),[...]

So putting this in the mathematical notation:

C[i] = (M[i]+K[i]) mod len(M)

C[0] = (4 + 21) % 26 = 25
C[1] = (13 + 6) % 26 = 19
C[2] = (20 + 7) % 26 = 1
[...]

So the letter "E" in position 4 in M[] will be replaced by the letter in position 25 in K[], which is "A". The same way, the letter "N" in position 13 in M[] will be replaced by the letter in position 19 in K[], which is "U", and so on...

E -> K[25] ->A
N -> K[19] ->U
U -> K[1] ->C
N -> K[5] ->G
L -> K[14] ->P 
U -> K[15] ->Q
G -> K[12] ->N
[...]

Decryption:

Decryption works pretty much the same way... The message is calculated this way:

M[i] = (C[i]-K[i]) mod len(M)

Let's check step by step.. This is our input data:

INPUT: AU CG PQNIK HA SI FEJJPT
KEY:   WH IT EWHIT EW HI TEWHIT
TUPLE: ('A', 'W'),('U', 'H'),('C', 'I'),('G', 'T'), ('P', 'E'),('Q', 'W'),('N', 'H'),('I', 'I'),('K', 'T'),('H', 'E'),[...]

We have to look for the positon of the each letter (of each tuple) in alphabet K[]:

1st tuple: Position of letter "A" and "W" in K[], 25 and 21.
2nd tuple: Position of letter "U" and "H" in K[], 19 and 6.
3rd tuple: C,I -> 1, 7

Now, coming back to the formula:

M[0] = (C[0]-K[0]) mod len(M) = (25 - 21) % 26 = 4 
M[1] = (C[1]-K[1]) mod len(M) = (19 - 6) % 26 = 13  
M[2] = (C[2]-K[2]) mod len(M) = (1 - 7) % 26 = 20 
M[3] = (C[3]-K[3]) mod len(M) = (5 - 18) % 26 = 13 

And looking for those positions in our reference alphabet M[]:

A -> M[4] -> E 
U -> M[13] -> N 
C -> M[20] -> U 
G -> M[13] -> N 
P -> M[11] -> L 
Q -> M[20] -> U 
N -> M[6] -> G 
I -> M[0] -> A 
K -> M[17] -> R 
[...]

Let put this into python code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/env python
import string

mykey="WHITE"
input_text="en un lugar de la mancha de cuyo nombre no quiero acordarme"
code_text="AU CG PQNIK HA SI FEJJPT HA JCRS JVUUVA UW JYELZH EYVZWENTM"

# Alphabet used as reference (M)
# ABCDEFGHIJKLMNOPQRSTUVWXYZ
source = string.ascii_uppercase

# Key alphabet (K) shifted 1 position to the left
# BCDEFGHIJKLMNOPQRSTUVWXYZA
shift = 1
matrix = [ source[(i + shift) % 26] for i in range(len(source)) ]

def coder(thistext):
    ciphertext = []
    control = 0

    for x,i in enumerate(input_text.upper()):
        if i not in source: 
            #If the symbol is not in our reference alphabet, we simply print it
            ciphertext.append(i)
            continue
        else:
            #Wrap around the mykey string 
            control = 0 if control % len(mykey) == 0 else control 

            #Calculate the position C[i] = (M[i]+K[i]) mod len(M)
            result = (source.find(i) + matrix.index(mykey[control])) % 26

            #Add the symbol in position "result" to be printed later
            ciphertext.append(matrix[result])
            control += 1

    return ciphertext

def decoder(thistext):
    control = 0
    plaintext = []

    for x,i in enumerate(code_text.upper()):
        if i not in source: 
            #If the symbol is not in our reference alphabet, we simply print it
            plaintext.append(i)
            continue
        else:
            #Wrap around the mykey string 
            control = 0 if control % len(mykey) == 0 else control 

            #Calculate the position M[i] = (C[i]-K[i]) mod len(M)
            result = (matrix.index(i) - matrix.index(mykey[control])) % 26

            #Add the symbol in position "result" to be printed later
            plaintext.append(source[result])
            control += 1

    return plaintext

# Print results
print("Key: {0}".format(mykey))
print("\nDecode text:")
print("-> Input text: {0}".format(input_text))
print("-> Coded text: {0}".format(''.join(coder(input_text))))

# Print results
print("\nDecode text:")
print("-> Input text: {0}".format(code_text))
print("-> Decoded text: {0}".format(''.join(decoder(code_text)).lower()))

Code stored in GitHub

The script is pretty basic and simple to understand. There are two functions, and the key part is the calculation of result using the math formula shown above.

And see the result:

$ python Vigenere_cipher_mod.py
Key: WHITE

Decode text:
-> Input text: en un lugar de la mancha de cuyo nombre no quiero acordarme
-> Coded text: AU CG PQNIK HA SI FEJJPT HA JCRS JVUUVA UW JYELZH EYVZWENTM

Decode text:
-> Input text: AU CG PQNIK HA SI FEJJPT HA JCRS JVUUVA UW JYELZH EYVZWENTM
-> Decoded text: en un lugar de la mancha de cuyo nombre no quiero acordarme

There are tons of references about how to break this code on the internet. I found these two very interesting:

Later

PS: I hate markdown. Just a little bit...

Simple Vigenere cipher in Python (2)

See: - Part 1/3 - Part 3/3

Just a small update to my previous post about the Vigenere cipher

Following the same approach as in the cipher, I modified a few lines in the script to create the "decoder"... I won't paste the code here, because the script is 95% the same, but I have stored it in GITHUB.

Basically, some variables change:

  • coder: input_text="en un lugar de la mancha de cuyo nombre no quiero acordarme"
  • decoder: input_text="AU CG PQNIK HA SI FEJJPT HA JCRS JVUUVA UW JYELZH EYVZWENTM"

  • coder: ciphertext = []

  • decoder: cleartext = []

  • coder: print("-> Output text: {0}".format(''.join(ciphertext)))

  • decoder: print("-> Output text: {0}".format(''.join(cleartext)))

And the logic for the look up changes as well:

In the coder, we replace the letter in the input_text by the one in the matrix[n] :

for x,y in encryption_tuple:
    if source.find(x) == -1: 
        ciphertext.append(x)
    else:
        ref_row = matrix[0].index(y)
        ciphertext.append(matrix[ref_row][source.index(x)])

In the decoder, we look for the position (lets call it "y") of the letter in matrix[n] and replace it by the letter in the position "y" in the alphabet:

for x,y in encryption_tuple:
    if source.find(x) == -1: 
        cleartext.append(x)
    else:
        ref_row = matrix[0].index(y)
        cleartext.append(source[matrix[ref_row].index(x)])

The result is the expected:

-> Key: WHITE
-> Input text: AU CG PQNIK HA SI FEJJPT HA JCRS JVUUVA UW JYELZH EYVZWENTM
-> Output text: EN UN LUGAR DE LA MANCHA DE CUYO NOMBRE NO QUIERO ACORDARME

In the next (and last post) about Vigenere, I'll write another simple coder/decoder script but based in the mathematical concept

Laters!