Ssh – Puppet: ssh – authorized_keys – Permission denied

puppetssh

All of our ~/.ssh/authorized_keys were created with mode 0400 (user, read only). We want to manage these files with Puppet so I created the following:

class users {
 user { 'julia':
  home           => '/home/julia',
  ensure         => present,
  purge_ssh_keys => true,
 }
}

ssh_authorized_key { 'julia@dirty':
  ensure => present,
  user   => 'julia',
  type   => 'ssh-ed25519',
  key    => 'AAAAC3NzaC1lvvvvvvxxxxxO1mXiiyj3Af17MviiiiiiiifffffzU5e//e/ffff/y',
}

However, when I run 'puppet agent –test' on a node, I get the following error:

Error: Puppet::Util::FileType::FileTypeFlat could not write /home/julia/.ssh/authorized_keys: Permission denied - /home/julia/.ssh/authorized_keys
Error: /Stage[main]/Profile::Base/Ssh_authorized_key[julia@dirty]: Could not evaluate: Puppet::Util::FileType::FileTypeFlat could not write /home/julia/.ssh/authorized_keys: Permission denied - /home/julia/.ssh/authorized_keys

I am able to "patch" the issue with the following:

file { "/home/julia/.ssh/authorized_keys":
    ensure => present,
    mode => '0600',
}

I'm surprised this is a problem. I thought this would work with any valid mode on the file (0600 or 0400). I can't find anything in the forge module documentation about valid modes or modifying modes. The 'file' parameter is an acceptable workaround but it doesn't work as nested within the 'ssh_authorized_key' section, so not as neat as we'd like. Also, I'm not sure how to do this for many users.

Can you offer a suggestions for handling this a better way?

There are a few posts via search that ask this same issue but no good solutions. Here is one from 7 years ago. I don't think the patch ever made it in the code base: https://projects.puppetlabs.com/issues/5395

Best Answer

I think authorized_keys needs to be 0600. 0400 is read-only, which means even the user can't write it!

The reason the "mode" doesn't work in the ssh_authorized_key resource is that that resource only adds an entry, it doesn't manage the file.

In terms of workaround/managing lots of users, I'd do it like this (in Puppet 3, but I'm sure this is neater in Puppet4/5 using some iteration?):

define myuser (
  $user,
  $key,
) {
  user { $user:
    home           => "/home/${user}",
    ensure         => present,
    purge_ssh_keys => true,
  }
  file { "/home/${user}/.ssh/authorized_keys":
    ensure => file,
    mode => "0600",
    require => User[$user],
  }
  ssh_authorized_key { "${user}@${host}":
    ensure => present,
    user   => $user,
    type   => 'ssh-ed25519',
    key    => "${key}",
  }
}

which you can then use with:

node default {
  myuser { "shearn89":
    user => "shearn89",
    key => "somelongasciistring",
  }
}

You can also do some clever stuff with defining users (possibly in Hiera) and then creating the resources.

Or, you could consider using a tool like Ansible to run a task against your whole platform and fix the file. I've found that Ansible complements Puppet nicely when used for this sort of orchestration/one-off task.