SUDO using SSH Keys

*Warning: I offer no guarantees this will work for you, and mis-configuration could end up with no access to your system*

It’s really annoying if you’ve connected SSH using keys that you’re prompted for a password when trying to use sudo. Particularly when using scripts. You can certainly use the NOPASS option in sudoers, but for various reasons may not want to.

I’ve gone for the option of (if SSH Key then allow sudo, if not prompt for password) something you couldn’t do with the NOPASS option.

First install libpam-ssh-agent-auth

apt-get install libpam-ssh-agent-auth

Then edit /etc/pam.d/sudo adding the following above the first sessions line:

auth [success=3 default=ignore] pam_ssh_agent_auth.so file=/etc/ssh/sudo_authorized_keys

Next edit /etc/sudoers and add above the existing Defaults:

Defaults env_keep += "SSH_AUTH_SOCK"

Finally edit /etc/ssh/sudo_authorized_keys and add your key.
It’s recommended you set the permission on this file to root only.

Now without closing your current connection, test the setup with a new ssh session. You should be able to connect and sudo without a password.
If you have password authentication enabled for connection normally, test this is still working, and when you use sudo you should be prompt again for the password.

This is working for me on Ubuntu, but as the warning above incorrect configuration may result in locking yourself out.

Ansible Part 1

I already have a Droplet for management so I’m going to be using this for Ansible and a new droplet to test some deployments. I’ve done the following on the server:

add-apt-repository ppa:rquillo/ansible
apt-get update
apt-get install ansible

I have no doubt that I will learn I’ve done bits wrong as I get further in, but I’m going to start with the following hosts config

[initial]
C3PO-1

[balancers]

[backends]

[databases]

[fileservers]

So the first thing I’m going to tackle is setting up new users. I’ve been playing with it for about an hour, although I got the user created very quickly I hit a problem with my setup. I need to send multiple ssh keys for some users (we use different keys on PC’s, Laptops, Mobiles). Every example I found seemed to a) want to pull a key from a file, b) just use one key.

After quite some playing, and trying different things I found a way. This in turn meant I had to slightly change the create user bit of the playbook.

Here’s the users.yml playbook so far

---
- hosts: all

  tasks:
    - name: Add Users from group_vars file
      action: user name={{ item.name }} password={{ item.password }} shell={{ item.shell }} state={{ item.state }} update_password=always
      with_items: users

    - name: Add SSH User Keys from group_vars files
      authorized_key: user={{ item.0.name }} key='{{ item.1 }}'
      with_subelements:
        - users
        - authorized

and uses a group_vars file (group_vars/initial)

---

users:
  - name: NAME
    password: HASHED_PASSWD
    authorized:
      - ssh-rsa SSH_KEY_1
      - ssh-rsa SSH_KEY_2
      - ssh-rsa SSH_KEY_3
      - ssh-rsa SSH_KEY_4
    shell: /bin/bash
    state: present

I did think about pulling the keys in from the authorized_keys files, but not all users are allowed on the management, so I’d have to keep files for them and if I’m going that far, I may as well just keep them in group_vars. It doesn’t look as nice if you cat the file but it’s structured and makes sense.

The last thing I want to do is set out add the user to some groups.

This was nice and easy, add the groups to the group_vars file

    groups: sudo,www-data

Then change the users.yml to add the groups

    action: user name={{ item.name }} password={{ item.password }} shell={{ item.shell }} state={{ item.state }} groups={{ item.groups }} update_password=always

I was worried that it may screw up the users own group as the manual says it delete’s all other groups except the primary, since I haven’t told it a primary using ‘group’ I thought it may be a problem, but thankfully it’s not this just worked.

Well I thought at this point I was pretty finished. Ha not a chance. I added a user for ansible to be able to connect as since I’ll be removing root ssh access. This means I’m going to need to let ansible sudo so I’d best sort that now. Here’s a bit of code I found and changed slightly. Make sure you change the username in the sudoers.d/ansible file

Appended to the end of users.yml

  - name: Ensure /etc/sudoers.d directory is present
    file: path=/etc/sudoers.d state=directory

  - name: Ensure /etc/sudoers.d is scanned by sudo
    action: lineinfile dest=/etc/sudoers regexp="#includedir\s+/etc/sudoers.d" line="#includedir /etc/sudoers.d"

  - name: Add ansible user to the sudoers
    action: 'lineinfile dest=/etc/sudoers.d/ansible state=present create=yes regexp="ansible .*" line="USERNAME ALL=(ALL) NOPASSWD: ALL"'

  - name: Ensure /etc/sudoers.d/ansible file has correct permissions
    action: file path=/etc/sudoers.d/ansible mode=0440 state=file owner=root group=root

On first run you’d use root to connect up. Then you would use

ansible-playbook users.yml -u USERNAME -s

All working. It’s taken about 2 hours to get to the point of deploying a couple of users automatically. I’m not so sure this has saved me time in the long run 🙂 but it’s the first step in a much bigger project. I’m kind of glad it wasn’t just copy and paste others code and stuff broke, it gave me a chance to understand a bit more.

Part 2 will be coming soon. There we’ll lock down SSHd and apply the default firewall rules.

Raspberry PI – LDAP Auth

Using Rasbian 20-12-2013 with updates

Install libnss-ldap

apt-get install libnss-ldap

Once complete you’ll be prompted for ldap details

ldap server e.g ldap://192.168.1.3/ ldap://192.168.1.2/
base dn e.g dc=system,dc=local
ldap version e.g 3
Does LDAP require login e.g No
Special LDAP privileges for Root e.g No

Once you’ve given the ldap details you need to update nsswitch.conf

nano -w /etc/nsswitch.conf

Previous config:

passwd:         compat
group:          compat
shadow:         compat

hosts:          files dns

networks:       files

protocols:      db files
services:       db files
ethers:         db files
rpc:            db files

netgroup:       nis

New config:

#passwd:         compat
passwd:         files ldap
#group:          compat
group:          files ldap
#shadow:         compat
shadow:         files ldap

hosts:          files dns

networks:       files

protocols:      db files
services:       db files
ethers:         db files
rpc:            db files

netgroup:       nis

Then we add the following so that home directories are automatically created

nano -w /usr/share/pam-configs/my_mkhomedir
Name: activate mkhomedir

Default: yes
Priority: 900
Session-Type: Additional
Session:
required                        pam_mkhomedir.so umask=0022 skel=/etc/skel

Apply the above using

pam-auth-update

To make sure everything is applied and the cache daemon doesn’t screw about I reboot. Once reboot login worked fine. A few commands that can help see what’s happening

getent passwd
getent group
tail /var/log/auth.log

Ubuntu LDAP Authentication (You are required to change your password immediately (password aged)) Part 2

In an earlier post I was encountering password problems when authenticating via OpenLDAP. This was prompting me to change my password while login onto certain servers but not all. The change prompt would then disappear after typing the current password and close the putty session.

Having resolved that particular problem I’m left with another. Although the password change is successful I now have to change the password on each login.

When I encountered the first problem a few months back I thought it was to do with the LDAP ACL. I think I was partly right as this is a continuation of that problem and it does look like this will be ACL related.

So looking at what information I can pull together, looking at the shadow information:-

root@Exxxxxxxx:~# getent shadow
root:*:::45::::
nobody:*:::::::
{username}:*:::365:::16177:

Using slapcat to pull all the information off ldap below are the relevant bits:-

shadowMax: 365
shadowExpire: 16177
shadowLastChange: 15921

So it looks like the shadowLastChange isn’t allowed to be viewed. I found someone else recommending that you make shadowLastChange readable by all. Below is the current ACL:-

dn: olcDatabase={1}hdb,cn=config
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn=”cn=admin,dc=domain,dc=local” write by * none
olcAccess: {1}to dn.base=”” by * read
olcAccess: {2}to * by self write by dn=”cn=admin,dc=domain,dc=local” write by * read

And here is the configuration that supposed to work (I say supposed to as I’m writing this while doing):-

dn: olcDatabase={1}hdb,cn=config
olcAccess: {0}to attrs=userPassword by self write by anonymous auth by dn=”cn=admin,dc=domain,dc=local” write by * none
olcAccess: {1}to attrs=shadowLastChange by self write by dn=”cn=admin,dc=domain,dc=local” write by * read
olcAccess: {2}to dn.base=”” by * read
olcAccess: {3}to * by self write by dn=”cn=admin,dc=domain,dc=local” write by * read

I’m not going to address any security concerns on making this field readable, for me it’s minimal.
So how do I change the ACL from the 1st to the 2nd. Make a new text file:-

nano -w auth_new.ldif
dn: olcDatabase={1}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword by self write by anonymous auth by dn="cn=admin,dc=domain,dc=local" write by * none
olcAccess: {1}to attrs=shadowLastChange by self write by dn="cn=admin,dc=domain,dc=local" write by * read
olcAccess: {2}to dn.base="" by * read
olcAccess: {3}to * by self write by dn="cn=admin,dc=domain,dc=local" write by * read

Make sure to change the dn to your specific setup. Failure to do so may result in you loosing admin access. Useful command:-

ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(olcAccess=*)' olcAccess
Next you modify the ldap using:-

ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f auth_new.ldif

Now when I checkout the shadow information I get:-

root@Exxxxxxxx:~/ldap# getent shadow
root:*:15797::45::::
nobody:*:::::::
{username}:*:15921::365:::16177:

Now when I login I’m not being prompted to change my password. I’m not entirely sure if this is right or wrong anymore as I’ve been changing my password all night, so I guess I’ll just wait for a few user accounts to expire and check that it does all work.

Update: It does work. I tested it with a users account that was having problems login into one of the servers, they were still prompted for their ldap password and told they must change it. Did that and then closed putty and tried again, logged in with the new password and wasn’t reprompted to change it again.

Ubuntu LDAP Authentication (You are required to change your password immediately (password aged))

Been hitting a problem on one of my servers for a while, when trying to login users keep getting prompted to change their password but it just closes putty after they retype their password.

I thought I narrowed it down to an ldap option roobinddn, I use this on some of my servers (those I consider secure) For the servers that I dont have the rootbinddn setup for, they receive the password change prompt for those that have it set they just allow login.
I looked at it a few months back but never had the time to really investigate and resolve it. I thought it had something to do with the ldap ACL permissions that the user doesn’t have access to the password fields for their own account. However looking at it today I think I may be only partly correct.

If I run login {username} I get the below:-

root@Exxxxxxxxx:~# login {username}
Password:
You are required to change your password immediately (password aged)
Enter login(LDAP) password:

Authentication information cannot be recovered

 I haven’t seen the ‘Authentication information cannot be recovered’ before as putty always closes. Checking out this error (I google every error) I found the solution was installing libpam-cracklib:-

apt-get install libpam-cracklib 

So now when I run login {username} I get:-

root@Exxxxxxxxx:~# login {username}
Password:
You are required to change your password immediately (password aged)
Enter login(LDAP) password:
New password:
Retype new password:
LDAP password information changed for {usernae}
Last login: Sun Aug 4 04:48:45 BST 2013 on pts/1

And a nice bash prompt.
Now onto problem #2, although I can now login after changing the password I get the password change prompt each login. Changing the password does take as login in the 2nd time uses the new password. So I think it’s now down to the ldap ACL for shadowLastChange so I’m going to investigate that, and will put anything to correct that one in another post.